C# CsvHelper:WriteRecord 抛出 "ConfigurationException: Types that inherit IEnumerable cannot be auto mapped"

C# CsvHelper: WriteRecord throws "ConfigurationException: Types that inherit IEnumerable cannot be auto mapped"

这是我的原始代码,不使用 CsvHelper 写入 CSV 文件。

 public static void Write(string file, List<PayRecord> payrecords) {
   using(StreamWriter sw = new StreamWriter(file)) {
     sw.WriteLine("EmployeeId,Gross,Tax,Net");
     foreach(PayRecord c in payrecords) {
       string line = string.Format("{0},{1},{2},{3}",
         c.Id,
         c.Gross,
         c.Tax,
         c.Net);
       sw.WriteLine(line);
     }
   }
 }

这是相同的代码,但是这次使用 CsvHelper:

public static void Write(string file, List<PayRecord> payrecords)
{
    using (StreamWriter sw = new StreamWriter(file))
    using (CsvWriter cw = new CsvWriter(sw, CultureInfo.CurrentCulture))
    {
        cw.WriteHeader<PayRecord>();
        foreach (var c in payrecords)
        {
            string line = string.Format("{0},{1},{2},{3}",
                c.Id,
                c.Gross,
                c.Tax,
                c.Net);
            cw.WriteRecord(line);

        }
    }
}

但我遇到了如下异常:

Unhandled exception. CsvHelper.Configuration.ConfigurationException: Types that inherit IEnumerable cannot be auto mapped. Did you accidentally call GetRecord or WriteRecord which acts on a single record instead of calling GetRecords or WriteRecords which acts on a list of records?
   at CsvHelper.CsvWriter.WriteRecord[T](T record)

和:

Unhandled exception. System.ArgumentNullException: Value cannot be null. (Parameter 'source')
   at System.Linq.ThrowHelper.ThrowArgumentNullException(ExceptionArgument argument)
   at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source)
   at CsvHelper.Configuration.ClassMap.AutoMapConstructorParameters(ClassMap map, CsvContext context, LinkedList`1 mapParents, Int32 indexStart)
   at CsvHelper.Configuration.ClassMap.AutoMapConstructorParameters(ClassMap map, CsvContext context, LinkedList`1 mapParents, Int32 indexStart)
   at CsvHelper.Configuration.ClassMap.AutoMap(CsvContext context)
   at CsvHelper.CsvContext.AutoMap(Type type)
   at CsvHelper.CsvWriter.WriteHeader(Type type)
   at CsvHelper.CsvWriter.WriteHeader[T]()

怎么了?

您正在尝试将 string 写为记录。

cw.WriteRecord(line);

我无法重现您的 ArgumentNullException 但我知道即使修复了该问题,您的代码仍然无法正常工作。

以上将抛出 CsvHelper.Configuration.ConfigurationException,因为 string 被 class 编辑为单个字段,而 CsvHelper.WriteRecord 更适合 class 而不是string.

其次,CsvWriter.WriteHeader 不会将“光标”移动到下一行,因此您需要使用 CsvWriter.NextRecord() 否则您的数据将与您的 header 在同一行.

以下代码有效:

  public static void Write(string file, List<PayRecord> payrecords) {
    using(StreamWriter sw = new StreamWriter(file))
    using(CsvWriter cw = new CsvWriter(sw, CultureInfo.CurrentCulture)) {
      cw.WriteHeader<PayRecord>();
      cw.NextRecord();

      foreach(var c in payrecords) {
        cw.WriteRecord(line);
      }
    }
}

然而,更好的办法是不要手动编写header,使用CsvHelper.WriteRecords并传递[=的整个collection 83=] 如下所示。

这会导致正确使用 CsvHelper.WriteRecords,同时编写正确的 header。

的代码更小、更清晰、更高效

更好:

public static void Write(string file, List<PayRecord> payrecords)
{
    using (StreamWriter sw = new StreamWriter(file))
    using (CsvWriter cw = new CsvWriter(sw, CultureInfo.CurrentCulture))
    {
        cw.WriteRecords(payrecords);
    }
}

更好?

要在不阻塞主线程的情况下执行 I/O 操作(写入 CSV 文件),请使用 CsvHelper.WriteRecordsAsync,使用 await using 不阻塞资源清理并使您的方法 async才能await来电。

我还会使用 ICollection<PayRecord>,这样如果您将 List<PayRecord> 更改为实现 ICollection 的任何其他类型,则无需更改方法。

奶油色:

public static async Task WritePayRecords(string file, ICollection<PayRecord> payrecords)
{
    await using (StreamWriter sw = new StreamWriter(file))
    await using (CsvWriter cw = new CsvWriter(sw, CultureInfo.CurrentCulture))
    {
        if (payrecords == null)
            throw new ArgumentNullException(nameof(payrecords), "Collection of pay records cannot be null");

        await cw.WriteRecordsAsync(payrecords);
    }
}

上面的代码甚至可以使用 null 字段,null objects 并且如果 collection 是 null 也会抛出异常(因为否则,CsvHelper 将抛出一个)。

希望对您有所帮助!