如何使用CsvHelper编写一个继承自DynamicObject的类?

3

我希望使用动态类型对象写入CSV文件。

在CsvWriter.WriteObject方法中,我收到了“CsvHelper.CsvWriterException”异常,并显示以下消息:“未映射任何属性到类型‘WpmExport.DynamicEntry’。”

这是我尝试使用的类:

public class DynamicEntry : DynamicObject
{
    private Dictionary<string, object> dictionary = new Dictionary<string, object>();

    public override bool TryGetMember(
        GetMemberBinder binder, out object result)
    {
        string name = binder.Name.ToLower();
        return dictionary.TryGetValue(name, out result);
    }

    public override bool TrySetMember(
        SetMemberBinder binder, object value)
    {
        dictionary[binder.Name.ToLower()] = value;
        return true;
    }

    public override IEnumerable<string> GetDynamicMemberNames()
    {
        return dictionary.Keys.AsEnumerable();
    }
}

有没有任何想法或者工作示例?在http://joshclose.github.io/CsvHelper/的文档中提到这是可能的,但并未提供任何指导。

TIA

2个回答

4
该功能尚不存在。您可以写dynamic,但不能写DynamicObject。您可以在此处查看有关该主题的帖子。https://github.com/JoshClose/CsvHelper/issues/187 一旦实现了这个功能,我会更新答案并注明它所在的版本。
更新
此功能将在3.0版本中提供。您可以从NuGet中尝试当前的3.0-beta版本。

2

因为我无法等待第3.0版(和CsvHelper.Excel支持它),所以我找到了一个临时解决方案。

已经得到导出类:

public partial class EntryReportInventory
{
    public Guid DeviceId { get; set; }
    [ReportProperty]
    public string DeviceName { get; set; }

    public Dictionary<string, object> InventoryValues { get; set; }

    public EntryReportInventory(Device device, Dictionary<string, object> inventoryValues)
    {
        this.DeviceId = device.Id;
        this.DeviceName = device.Name;

        this.InventoryValues = inventoryValues;
    }
}

创建映射器:

Type genericClass = typeof(DefaultCsvClassMap<>);
Type constructedClass = genericClass.MakeGenericType(typeof(EntryReportInventory));
                return (CsvClassMap)Activator.CreateInstance(constructedClass);

现在,让我们来看一下魔法。我遍历所有属性。

foreach (PropertyInfo property in mapping)
            {
...
if (isInventoryReportBaseType && typeof(Dictionary<string, object>).IsAssignableFrom(property.PropertyType))
                {
                    var dataSource = (ReportInventoryBase)Activator.CreateInstance(entityType, dbContext);

                    foreach (var item in dataSource.ColumnNameAndText)
                    {
                        var columnName = item.Key;

                        var newMap = new CsvPropertyMap(property);
                        newMap.Name(columnName);
                        newMap.TypeConverter(new InventoryEntryListSpecifiedTypeConverter(item.Key));

                        customMap.PropertyMaps.Add(newMap);
                    }
...
}

我的转换器是:
    public class InventoryEntryListSpecifiedTypeConverter : CsvHelper.TypeConversion.ITypeConverter
    {
        private string indexKey;
        public InventoryEntryListSpecifiedTypeConverter(string indexKey)
        {
            this.indexKey = indexKey;
        }

        public bool CanConvertFrom(Type type)
        {
            return true;
        }

        public bool CanConvertTo(Type type)
        {
            return true;
        }

        public object ConvertFromString(TypeConverterOptions options, string text)
        {
            throw new NotImplementedException();
        }

        public string ConvertToString(TypeConverterOptions options, object value)
        {
            var myValue = value as Dictionary<string, object>;
            if (value == null || myValue.Count == 0) return null;

            return myValue[indexKey] + "";
        }
    }

不知道为什么,但是多次传递相同的属性是有效的。 就是这样 :) 您只需要在之前拥有一个列表(此处为dataSource.ColumnNameAndText,从外部来源填充),以识别列/值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接