【问题标题】:How do you use CsvHelper to write a class derived from DynamicObject?如何使用 CsvHelper 编写从 DynamicObject 派生的类?
【发布时间】:2014-09-27 06:46:21
【问题描述】:

我希望使用动态类型的对象来写入 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

【问题讨论】:

    标签: c# .net dynamic csvhelper


    【解决方案1】:

    该功能尚不存在。你可以写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,从外部来源填充)来识别列/值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-23
        • 1970-01-01
        • 1970-01-01
        • 2020-05-23
        • 1970-01-01
        相关资源
        最近更新 更多