首页 > 解决方案 > 从动态集合创建地图不再有效:无法将 System.String 类型的对象转换为 System.Object)

问题描述

我们正在将遗留代码移植到 dotnet 标准,并面临 [我相信] CsvHelper 2.5.0 net451 中不存在的问题。

问题似乎是 CsvReader 无法解决映射中基础属性的正确 ReturnType 并试图将它们全部映射到 System.Object

我已经设法在您的解决方案中通过单元测试来重现它:

[TestMethod]
public void CanCreateMapsFromDynamicList()
{
    var data = new List<string[]>
    {
        new[] { "Col1", "Col2" },
        new[] { "1", "one" },
        new[] { "2", "two" }
    };

    var queue = new Queue<string[]>(data);
    var parserMock = new ParserMock(queue);

    var csvReader = new CsvReader(parserMock);
    csvReader.Configuration.RegisterClassMap<SomeTypeClassMap>();

    var records = csvReader.GetRecords<SomeType>().ToList();

    Assert.IsNotNull(records);
    Assert.AreEqual(2, records.Count);

}

public class SomeTypeClassMap : ClassMap<SomeType>
{
    public SomeTypeClassMap()
    {
        Map(x => x.Id).Ignore();
        var t = new SomeType();

        foreach (var mapping in t.Mappings)
        {
            Map(mapping);
        }
    }
}

public class SomeType
{
    public int Id { get; set; }
    public string Col1 { get; set; }
    public string Col2 { get; set; }

    public IEnumerable<Expression<Func<SomeType, dynamic>>> Mappings =>
        new List<Expression<Func<SomeType, dynamic>>> {i => i.Col1, i => i.Col2};
}

报错:

测试方法 CsvHelper.Tests.CsvReaderMappingTestsRuslan.CanCreateMapsFromDynamicList 抛出异常:System.InvalidCastException:无法将“CsvHelper.Configuration.MemberMap2 [CsvHelper.Tests.CsvReaderMappingTestsRuslan+SomeType,System.String]”类型的对象转换为“CsvHelper.Configuration.MemberMap2” [CsvHelper.Tests.CsvReaderMappingTestsRuslan+SomeType,System.Object]'。

PS我尝试将“映射”属性更改为静态并获得相同的结果。

标签: c#.net-standardcsvhelpercsvreader

解决方案


通过添加此重载方法解决了它:

    public virtual MemberMap Map<T>( Expression<Func<T, object>> expression, bool useExistingMap = true )
    {
        var stack = ReflectionHelper.GetMembers(expression);
        if (stack.Count == 0)
        {
            throw new InvalidOperationException("No members were found in expression '{expression}'.");
        }

        ClassMap currentClassMap = this;
        MemberInfo member;

        if (stack.Count > 1)
        {
            // We need to add a reference map for every sub member.
            while (stack.Count > 1)
            {
                member = stack.Pop();
                Type mapType;
                var property = member as PropertyInfo;
                var field = member as FieldInfo;
                if (property != null)
                {
                    mapType = typeof(DefaultClassMap<>).MakeGenericType(property.PropertyType);
                }
                else if (field != null)
                {
                    mapType = typeof(DefaultClassMap<>).MakeGenericType(field.FieldType);
                }
                else
                {
                    throw new InvalidOperationException("The given expression was not a property or a field.");
                }

                var referenceMap = currentClassMap.References(mapType, member);
                currentClassMap = referenceMap.Data.Mapping;
            }
        }

        // Add the member map to the last reference map.
        member = stack.Pop();

        return currentClassMap.Map( typeof(TClass), member, useExistingMap );
    }

PR 提出https://github.com/JoshClose/CsvHelper/pull/1505


推荐阅读