带有非默认构造函数的 CsvHelper

如何解决带有非默认构造函数的 CsvHelper

我的问题如下。我想在 WPF c# 下的 CsvHelper 的帮助下将类属性写入 CSV 文件,然后再读回它们。引用的类之一具有非认的参数化构造函数。如何让 CsvHelper 正确调用其构造函数

因此我使用以下地图文件

public class TradeLogRecMap : ClassMap<TradeLogRec>
{
    public TradeLogRecMap()
    {
        AutoMap(CSVConfig);
    }
}

有了这些类和结构

public class Liquidity
{
    static readonly Dictionary<int,string> Values = new Dictionary<int,string> 
    { 
        {0,"None"},{1,"Added Liquidity"},{2,"Removed Liquidity"},{3,"Liquidity Routed Out" }
    };

    public Liquidity(int p)
    {
        Value = Values.ContainsKey(p) ? p : 0;
    }

    public int Value { get; set; }

    public override string ToString()
    {
        return Values[Value];
    }
}

public class Execution
{
    public Liquidity LastLiquidity { get; set; }

    public Execution()
    {
        LastLiquidity = new Liquidity(0);
    }

}

public struct TradeLogRec
{
    public Execution execution { set; get; }
}

当我写 CSV 文件时看起来还可以。但是读回来它说它错过了标题“p”。向 CSV 文件添加“p”标题可以解决这个问题,但这样做不是一种选择。还添加一个认构造函数

    public Liquidity()
    {
    }

解决问题。但这不是以太坊的选项。

为什么它总是期望标题“p”?

是否可以通过地图文件中的一些构造函数设置或CvsHelper配置来解决

还是bug?

解决方法

从 CsvHelper 27.1.1 开始,当 CsvHelper 在读取期间尝试构造类时,它将使用无参数构造函数(如果存在)。如果不存在,它将使用带有 most parameters [1] 的参数化构造函数。当调用参数化构造函数时,CSV 列将通过参数名称的精确匹配与构造函数参数匹配。在您的 Liquidity 类中,您要映射到“值”列的参数名为 p,因此无法进行匹配。

那么,您有什么选择?

首先,如果您可以修改您的 Liquidity 类,您可以将 p 构造函数参数重命名为 Value

public Liquidity(int Value)
{
    // Make the constructor parameter name match the property name exactly for CsvHelper
    this.Value = Values.ContainsKey(Value) ? Value : 0;
}

这样做后,一切都会正常进行。演示小提琴 #1 here

其次,您可以修改 Liquidity 以将 [CsvHelper.Configuration.Attributes.Name("Value")] 添加到 p

public Liquidity([CsvHelper.Configuration.Attributes.Name("Value")] int p)
{
    Value = Values.ContainsKey(p) ? p : 0;
}

演示小提琴 #2 here

第三,如果您不能以任何方式修改您的类,您可以覆盖 AutoMap 生成的默认引用映射并为 Liquidity 提供您自己的映射。

创建以下 ClassMap<Liquidity>

public class LiquidityMap : ClassMap<Liquidity>
{
    public LiquidityMap()
    {
        Map(m => m.Value);
        Parameter("p").Name(nameof(Liquidity.Value));
    }
}   

并修改 TradeLogRecMap 以使用它,如下所示:

public class TradeLogRecMap : ClassMap<TradeLogRec>
{
    public TradeLogRecMap()
    {
        // Automap TradeLogRecMap
        AutoMap(CSVConfig);  // CSVConfig was not shown in your question,I used new CsvConfiguration(CultureInfo.InvariantCulture) { }
        // Get the reference map for Execution
        var executionRefMap = ReferenceMaps.Find<TradeLogRec>(m => m.execution);
        // Get its reference map for LastLiquidity
        var liquidityRefMap = executionRefMap.Data.Mapping.ReferenceMaps.Find<Execution>(m => m.LastLiquidity);
        // Remove the auto-generated reference map for LastLiquidity
        executionRefMap.Data.Mapping.ReferenceMaps.Remove(liquidityRefMap);
        // And add a reference map for LastLiquidity using LiquidityMap
        executionRefMap.Data.Mapping.ReferenceMaps.Add(new MemberReferenceMap(liquidityRefMap.Data.Member,new LiquidityMap()));
    }
}   

演示小提琴 #3 here

最后,您可以修改 CsvConfiguration.PrepareHeaderForMatch 以自动将名为“p”的任何列重新映射到“Value”:

public static CsvConfiguration CSVConfig => 
    new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        PrepareHeaderForMatch = a => a.Header == "p" ? nameof(Liquidity.Value) : a.Header,};

然后在构建您的 CsvReader 时使用它:

public static List<TradeLogRec> DeserializeTradeLogRecMapFromCsv(TextReader reader)
{
    using (var csv = new CsvReader(reader,CSVConfig))
    {
        csv.Context.RegisterClassMap<TradeLogRecMap>();
        return csv.GetRecords<TradeLogRec>().ToList();
    }           
}

这看起来有点笨拙,因为它将所有名为“Value”的列映射到“p”,而不仅仅是 Liquidity 的列 - 但它确实有效。演示小提琴 #4 here


[1] 此行为是通过 CsvConfiguration.ShouldUseConstructorParameterCsvConfiguration.GetConstructor 配置的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?