4

我确信它非常简单,但我正在努力弄清楚如何使用 CSVHelper 将数组写入文件。

例如,我有一堂课

public class Test
{
public Test()
{
data = new float[]{0,1,2,3,4};
}
 public float[] data{get;set;}
}

我希望将数据与每个数组值一起写入单独的单元格中。我在下面有一个自定义转换器,而是为一个单元格提供其中的所有值。

我究竟做错了什么?

public class DataArrayConverter<T> : ITypeConverter
{
    public string ConvertToString(TypeConverterOptions options, object value)
    {
        var data = (T[])value;

       var s = string.Join(",", data);

    }

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

    public bool CanConvertFrom(Type type)
    {
        return type == typeof(string);
    }

    public bool CanConvertTo(Type type)
    {
        return type == typeof(string);
    }
}
4

2 回答 2

4

要进一步详细说明Josh Close的答案,这里是IEnumerable在 CsvHelper 的最新版本(任何高于 3.0 的版本)中编写任何(包括数组和通用列表)所需的操作!


这里是被测试的类:

public class Test
{
    public int[] Data { get; set; }

    public Test()
    {
        Data = new int[] { 0, 1, 2, 3, 4 };
    }
}

以及一种显示如何保存的方法:

static void Main()
{
    using (var writer = new StreamWriter("db.csv"))
    using (var csv = new CsvWriter(writer))
    {
        var list = new List<Test>
        {
            new Test()
        };
        csv.Configuration.HasHeaderRecord = false;
        csv.WriteRecords(list);
        writer.Flush();
    }
}

这里的重要配置是csv.Configuration.HasHeaderRecord = false;. 只有使用此配置,您才能看到 csv 文件中的数据。

更多细节可以在CsvHelper的相关单元测试用例中找到。


如果您正在寻找一种解决方案来存储IEnumerable具有不同数量元素的类型属性,以下示例可能会有所帮助:

using CsvHelper;
using CsvHelper.Configuration;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace CsvHelperSpike
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var writer = new StreamWriter("db.csv"))
            using (var csv = new CsvWriter(writer))
            {
                csv.Configuration.Delimiter = ";";
                var list = new List<AnotherTest>
                {
                    new AnotherTest("Before String") { Tags = new List<string> { "One", "Two", "Three" }, After="After String" },
                    new AnotherTest("This is still before") {After="after again", Tags=new List<string>{ "Six", "seven","eight", "nine"} }
                };
                csv.Configuration.RegisterClassMap<TestIndexMap>();
                csv.WriteRecords(list);
                writer.Flush();
            }

            using(var reader = new StreamReader("db.csv"))
            using(var csv = new CsvReader(reader))
            {
                csv.Configuration.IncludePrivateMembers = true;
                csv.Configuration.RegisterClassMap<TestIndexMap>();
                var result = csv.GetRecords<AnotherTest>().ToList();
            }
        }

        private class AnotherTest
        {
            public string Before { get; private set; }
            public string After { get; set; }
            public List<string> Tags { get; set; }

            public AnotherTest() { }

            public AnotherTest(string before)
            {
                this.Before = before;
            }
        }

        private sealed class TestIndexMap : ClassMap<AnotherTest>
        {
            public TestIndexMap()
            {
                Map(m => m.Before).Index(0);
                Map(m => m.After).Index(1);
                Map(m => m.Tags).Index(2);
            }
        }
    }
}

通过使用,ClassMap可以再次启用HasHeaderRecord(默认)。需要注意的是,这个解决方案只有在元素数量不同的集合是最后一个属性时才有效。否则,集合需要具有固定数量的元素,并且ClassMap需要相应地进行调整。

此示例还展示了如何使用private set. 为此,使用csv.Configuration.IncludePrivateMembers = true;配置并在您的类上使用默认构造函数非常重要。

于 2019-07-05T18:03:01.373 回答
3

不幸的是,它不是那样工作的。由于您,在转换器中返回,它将引用该字段,因为它是单个字段的一部分。

目前,完成您想要的唯一方法是手动编写,这并不太可怕。

foreach( var test in list )
{
    foreach( var item in test.Data )
    {
        csvWriter.WriteField( item );
    }

    csvWriter.NextRecord();
}

更新

版本 3 支持读取和写入 IEnumerable 属性。

于 2014-10-01T21:35:23.680 回答