具有非默认构造函数的CsvHelper



我的问题如下。我想在WPFc#下的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";。添加一个";p〃;CSV文件的头解决了这个问题,但这样做不是一个选项。还添加了一个默认构造函数

public Liquidity()
{
}

解决了问题。但这不是一个选择以太。

为什么它期望标题";p〃;无论如何

是否可以通过映射文件或CvsHelper配置中的一些构造函数设置来解决此问题?

还是一个bug?

从CsvHelper 27.1.1开始,当CsvHelpers在读取期间尝试构造类时,它将使用无参数构造函数(如果存在(。如果不存在,它将使用带有大多数参数的参数化构造函数[1]。调用参数化构造函数时,CSV列通过参数名称的精确匹配与构造函数参数匹配。在CCD_ 1类中,您希望映射到";值";列名为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。

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

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

在这里演示小提琴#2。

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

创建以下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在这里。

最后,您可以修改CCD_ 13以自动重新映射任何名为"的列;p〃;至";值":

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

这看起来有点笨拙,因为它映射所有名为"的列;值";至";p〃;,不仅是Liquidity的列,而且它确实有效。演示小提琴#4在这里。


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

相关内容

  • 没有找到相关文章

最新更新