我正在尝试使用 CSVHelper 序列化由多个类构造的数据库,如下所示。我想通过添加有关单位的信息(在适当的时候)并对数据进行排序以使“名称”始终出现在前面,从而使 csv 更具可读性。其余的可以按任何顺序排列。
我有一个如下所示的类。
[DataContract(IsReference = true)]
public class OpaqueMaterial : LibraryComponent
{
[DataMember]
[Units("W/m.K")]
public double Conductivity { get; set; } = 2.4;
[DataMember]
public string Roughness { get; set; } = "Rough";
}
[DataContract]
public abstract class LibraryComponent
{
[DataMember, DefaultValue("No name")]
public string Name { get; set; } = "No name";
}
为了避免为每个类编写单独的读写函数,我正在使用模板化函数进行读写,如下所示:
public void writeLibCSV<T>(string fp, List<T> records)
{
using (var sw = new StreamWriter(fp))
{
var csv = new CsvWriter(sw);
csv.WriteRecords(records);
}
}
public List<T> readLibCSV<T>(string fp)
{
var records = new List<T>();
using (var sr = new StreamReader(fp))
{
var csv = new CsvReader(sr);
records = csv.GetRecords<T>().ToList();
}
return records;
}
然后我在代码中使用它来读取和写入:
writeLibCSV<OpaqueMaterial>(folderPath + @"\OpaqueMaterial.csv", lib.OpaqueMaterial.ToList());
List<OpaqueMaterial> inOpaqueMaterial = readLibCSV<OpaqueMaterial>(folderPath + @"\OpaqueMaterial.csv");
CSV 输出如下所示:
Conductivity, Roughnes, Name
2.4, Rough, No Name
我想成为:
Name, Conductivity [W/m.K], Roughness
No Name, 2.4, Rough
我知道可以使用以下 map 进行重新排序:
public class MyClassMap : ClassMap<OpaqueMaterial>
{
public MyClassMap()
{
Map(m => m.Name).Index(0);
AutoMap();
}
}
我想进行抽象,这样我就不必对每个类应用不同的映射。我找不到可以帮助添加自定义 header 的示例。任何建议或帮助将不胜感激。
最佳答案
您可以创建 ClassMap<T>
的通用版本这将自动检查类型 T
使用反射,然后根据它找到的属性以及可能附加或不附加到它的属性动态构造映射。
如果不太了解 CsvHelper 库,类似这样的东西应该可以工作:
public class AutoMap<T> : ClassMap<T>
{
public AutoMap()
{
var properties = typeof(T).GetProperties();
// map the name property first
var nameProperty = properties.FirstOrDefault(p => p.Name == "Name");
if (nameProperty != null)
MapProperty(nameProperty).Index(0);
foreach (var prop in properties.Where(p => p != nameProperty))
MapProperty(prop);
}
private MemberMap MapProperty(PropertyInfo pi)
{
var map = Map(typeof(T), pi);
// set name
string name = pi.Name;
var unitsAttribute = pi.GetCustomAttribute<UnitsAttribute>();
if (unitsAttribute != null)
name = $"{name} {unitsAttribute.Unit}";
map.Name(name);
// set default
var defaultValueAttribute = pi.GetCustomAttribute<DefaultValueAttribute>();
if (defaultValueAttribute != null)
map.Default(defaultValueAttribute.Value);
return map;
}
}
现在,您只需创建一个 AutoMap<T>
对于每种类型 T
您想要支持的内容。
我添加了 UnitsAttribute
的示例和 DefaultValueAttribute
,这应该会让您了解如何在需要更多属性时继续使用更多属性。
关于c# - 通过 CSVHelper 使用属性使 header 更易于阅读,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48509614/