文件帮助程序无法将转换后的字段映射到目标数组



我有以下记录(为简洁起见,缩小):

 [DelimitedRecord(",")]
    [IgnoreFirst]
    [IgnoreEmptyLines()]
    public class ImportRecord
    {
        [FieldQuoted]
        [FieldTrim(TrimMode.Both)]
        public string FirstName;
        [FieldQuoted]
        [FieldTrim(TrimMode.Both)]
        public string LastName;
        [FieldQuoted]
        [FieldTrim(TrimMode.Both)]
        [FieldOptional]
        [FieldConverter(typeof(TestPropertyConverter))]
        public int[] TestProperty;    
    }

转换器代码:

  public class TestPropertyConverter : ConverterBase
    {
        public override object StringToField(string from)
        {
              var ret = from.Split('|').Select(x => Convert.ToInt32(x)).ToArray();
              return ret;
        }
    }

因此,示例记录可以是:约翰, 史密斯, 1|2|3|4

它期望值 1,2,3,4 扩展并填充 TestProperty 数组。但是,我收到以下异常:

源数组中至少有一个元素无法强制转换为目标数组类型。

我试图调试代码,它似乎在 FieldBase 内的 ExtractFieldValue() 函数中爆炸了.cs它试图从函数中返回。下面这句话似乎是罪魁祸首:

res.ToArray(ArrayType);

它似乎期望"res"变量是目标类型数组,但它包含数组本身的 1 个元素。

任何人都可以建议我是否做错了或可能的解决方法?

另一种方法是在AfterReadRecord事件中处理解析。 当数组字段的分析很复杂时,这很有用。 (自定义转换器功能较弱,不会为您提供例如e.SkipThisRecord)。

[DelimitedRecord(",")]
//[IgnoreFirst]
[IgnoreEmptyLines()]
public class ImportRecord
{
    [FieldQuoted]
    [FieldTrim(TrimMode.Both)]
    public string FirstName;
    [FieldQuoted]
    [FieldTrim(TrimMode.Both)]
    public string LastName;
    [FieldQuoted]
    [FieldTrim(TrimMode.Both)]
    [FieldOptional]
    public string TestProperty;
    [FieldIgnored] // <-- this field is ignored by the FileHelpers engine
    public int[] ParsedTestProperty; 
}
class Program
{
    static void Main(string[] args)
    {
        var engine = new FileHelperEngine<ImportRecord>();
        engine.AfterReadRecord += engine_AfterReadRecord;
        string fileAsString = @"John, Smith, 1|2|3|4" + Environment.NewLine;
        ImportRecord[] validRecords = engine.ReadString(fileAsString);
        Assert.AreEqual("John", validRecords[0].FirstName);
        Assert.AreEqual("Smith", validRecords[0].LastName);
        Assert.AreEqual(new int[] { 1, 2, 3, 4 }, validRecords[0].ParsedTestProperty);
        Console.ReadKey();
    }
    static void engine_AfterReadRecord(EngineBase engine, AfterReadEventArgs<ImportRecord> e)
    {
        e.Record.ParsedTestProperty = e.Record.TestProperty.Split('|').Select(x => Convert.ToInt32(x)).ToArray();
    }
}

你不需要写转换器。 您只需要更改最后一个字段的字段分隔符。 以下示例有效:

[DelimitedRecord(",")]
//[IgnoreFirst]
[IgnoreEmptyLines()]
public class ImportRecord
{
    [FieldQuoted]
    [FieldTrim(TrimMode.Both)]
    public string FirstName;
    [FieldQuoted]
    [FieldTrim(TrimMode.Both)]
    public string LastName;
    [FieldQuoted]
    [FieldTrim(TrimMode.Both)]
    [FieldOptional]
    [FieldDelimiter("|")] // <-- here 
    public int[] TestProperty;
}
class Program
{
    static void Main(string[] args)
    {
        var engine = new FileHelperEngine<ImportRecord>();
        string fileAsString = @"John, Smith, 1|2|3|4" + Environment.NewLine;
        ImportRecord[] validRecords = engine.ReadString(fileAsString);
        Assert.AreEqual("John", validRecords[0].FirstName);
        Assert.AreEqual("Smith", validRecords[0].LastName);
        Assert.AreEqual(new int[] { 1, 2, 3, 4 }, validRecords[0].TestProperty);
        Console.ReadKey();
    }
}

很抱歉提出这个老问题,但我刚刚遇到了同样的问题,我找到了解决这个问题的更简单的方法。

文件助手似乎以特殊方式处理数组,并期望用DelimitedRecord属性指示的分隔符分隔值。因此,它尝试在每个分隔记录上调用自定义转换器,并期望您返回元素类型。

就我而言,我有任何位图(010100101001010101001010001101)字段,没有任何我想转换为bool[]的分隔符。我进入源代码,发现typeof(T).IsArray用于确定此行为。

因此,长话短说,将数组更改为列表就足够了。

而不是:

public int[] TestProperty;   

更改为:

public List<int> TestProperty;   

并且还修改自定义转换器以返回列表:

return from.Split('|').Select(x => Convert.ToInt32(x)).ToList();

最新更新