我有一个不可变的类,我想写入CSV文件并从中读取。问题是尽管已映射了对象并设置了允许其工作的配置,但在读取CSV时却出现了异常。

为此,我正在使用CsvHelper。不可变类如下所示。

public class ImmutableTest
{
    public Guid Id { get; }

    public string Name { get; }

    public ImmutableTest(string name) : this(Guid.NewGuid(), name)
    {
    }

    public ImmutableTest(Guid id, string name)
    {
        Id = id;
        Name = name;
    }
}

将其写入CSV文件没有问题,但是当我尝试从文件中读取它时,出现以下异常。



但是,我已经在下面的map类中映射了该类的成员。
public sealed class ImmutableTestMap : ClassMap<ImmutableTest>
{
    public ImmutableTestMap()
    {
        Map(immutableTest => immutableTest.Id)
            .Index(0)
            .Name(nameof(ImmutableTest.Id).ToUpper());

        Map(immutableTest => immutableTest.Name)
            .Index(1)
            .Name(nameof(ImmutableTest.Name));
    }
}

我还尝试通过以下配置将读取器配置为使用构造函数来构建对象。
Configuration config = new Configuration
{
    IgnoreBlankLines = true
};

config.RegisterClassMap<ImmutableTestMap>();
config.ShouldUseConstructorParameters = type => true;
config.GetConstructor = type => type.GetConstructors()
    .MaxBy(constructor => constructor.GetParameters().Length)
    .FirstOrDefault();

这些似乎都不起作用。我要去哪里错了?

完整的MCVE .NET Framework控制台示例

安装软件包
Install-Package CsvHelper
Install-Package morelinq

样例控制台程序
using System;
using System.IO;
using CsvHelper;
using CsvHelper.Configuration;
using MoreLinq;

namespace CsvTest
{
    class Program
    {
        static void Main()
        {
            Configuration config = new Configuration
            {
                IgnoreBlankLines = true
            };

            config.RegisterClassMap<ImmutableTestMap>();
            config.ShouldUseConstructorParameters = type => true;
            config.GetConstructor = type => type.GetConstructors()
                .MaxBy(constructor => constructor.GetParameters().Length)
                .FirstOrDefault();

            const string filePath = "Test.csv";
            using (FileStream file = new FileStream(filePath, FileMode.Create))
            using (StreamWriter fileWriter = new StreamWriter(file))
            using (CsvSerializer csvSerializer = new CsvSerializer(fileWriter, config))
            using (CsvWriter csvWriter = new CsvWriter(csvSerializer))
            {
                csvWriter.WriteHeader<ImmutableTest>();
                csvWriter.NextRecord();
                csvWriter.WriteRecord(new ImmutableTest("Test 1"));
                csvWriter.NextRecord();
                csvWriter.WriteRecord(new ImmutableTest("Test 2"));
                csvWriter.NextRecord();
            }

            using (FileStream file = new FileStream(filePath, FileMode.Open))
            using (StreamReader fileReader = new StreamReader(file))
            using (CsvReader csvReader = new CsvReader(fileReader, config))
            {
                foreach (ImmutableTest record in csvReader.GetRecords<ImmutableTest>())
                {
                    Console.WriteLine(record.Id);
                    Console.WriteLine(record.Name);
                    Console.WriteLine();
                }
            }
        }

        public sealed class ImmutableTestMap : ClassMap<ImmutableTest>
        {
            public ImmutableTestMap()
            {
                Map(immutableTest => immutableTest.Id)
                    .Index(0)
                    .Name(nameof(ImmutableTest.Id).ToUpper());

                Map(immutableTest => immutableTest.Name)
                    .Index(1)
                    .Name(nameof(ImmutableTest.Name));
            }
        }

        public class ImmutableTest
        {
            public Guid Id { get; }

            public string Name { get; }

            public ImmutableTest(string name) : this(Guid.NewGuid(), name)
            {
            }

            public ImmutableTest(Guid id, string name)
            {
                Id = id;
                Name = name;
            }
        }
    }
}

最佳答案

如果类型是不可变的,它将改用构造函数映射。您的构造函数变量名称必须与标题名称匹配。您可以使用Configuration.PrepareHeaderForMatch进行此操作。

void Main()
{
    var s = new StringBuilder();
    s.AppendLine("Id,Name");
    s.AppendLine($"{Guid.NewGuid()},one");
    using (var reader = new StringReader(s.ToString()))
    using (var csv = new CsvReader(reader))
    {
        csv.Configuration.PrepareHeaderForMatch = (header, indexer) => header.ToLower();
        csv.GetRecords<ImmutableTest>().ToList().Dump();
    }
}

public class ImmutableTest
{
    public Guid Id { get; }

    public string Name { get; }

    public ImmutableTest(string name) : this(Guid.NewGuid(), name)
    {
    }

    public ImmutableTest(Guid id, string name)
    {
        Id = id;
        Name = name;
    }
}

关于c# - CsvHelper和不可变类型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56991550/

10-11 14:24