csv C#配置文件帮助器:写入记录抛出“配置异常:无法自动Map继承IEnumerable的类型”

iqih9akk  于 2023-03-10  发布在  C#
关注(0)|答案(1)|浏览(175)

这是我的原始代码,不使用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]()

出什么事了?

yptwkmov

yptwkmov1#

您正尝试将string写入记录。

cw.WriteRecord(line);
我不可能重现您的ArgumentNullException,但我知道即使修复了这个问题,您的代码仍然无法工作。
上面的代码将抛出一个CsvHelper.Configuration.ConfigurationException,因为string被分类为单个字段& CsvHelper.WriteRecord更多地用于类,而不是string
其次,CsvWriter.WriteHeader不会将“光标”移动到下一行,因此您需要使用CsvWriter.NextRecord(),否则您的数据将与标题位于同一行。
下面的代码可以工作:

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(c);
      }
    }
}

但是,最好不要手动编写头文件,使用CsvHelper.WriteRecords并传递整个对象集合,如下所示。

这使得正确使用CsvHelper.WriteRecords的代码更小、更干净、更高效,同时还能编写正确的头文件。
这是 * 更好 *:

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对象,并且如果集合是null,还会抛出异常(否则,CsvHelper将抛出异常)。
希望能有所帮助!

相关问题