Страницы

Поиск по вопросам

пятница, 13 декабря 2019 г.

Маппинг классов в C# по имени свойств?

#c_sharp #linq


Как на C# или через LINQ сделать такое:

class A
{
    public string First { get; set; }
    public string Second { get; set; }
    //...
    //другие свойства
};

class B
{
    public string Third { get; set; }
    public string Four { get; set; }
    //...
    //другие свойства
};

class Result
{
    public string First { get; set; }
    public string Second { get; set; }
    public string Third { get; set; }
    public string Four { get; set; }

    //...
    //другие свойства
};


Как примапить A & B к Result?

Можно конечно написать вручную:

r.First = a.First;
r.Second = a.Second;
r.Third = b.Third;
r.Four = b.Four;


Но так слишком много писать, хотелось бы по короче и побыстрее.
    


Ответы

Ответ 1



Ответы-ссылки тут не приветствуются, но в этом случае без ссылки никак: AutoMapper. Package Manager: Install-Package AutoMapper C#: Mapper.CreateMap(); Mapper.CreateMap(); var a = new A() { First = "1", Second = "2" }; var b = new B() { Third = "3", Four = "4" }; var res = Mapper.Map(a); Mapper.Map(b, res); // 1, 2, 3, 4 или с динамическим маппингом: var a = new A() { First = "1", Second = "2" }; var b = new B() { Third = "3", Four = "4" }; var res = Mapper.DynamicMap(a); Mapper.DynamicMap(b, res);

Ответ 2



В таких случаях обычно используют рефлексию. Простой пример копирования публичных свойств с идентичными типами: static TTarget Copy(object source) where TTarget : new() { if (source == null) return default(TTarget); const BindingFlags publicInstance = BindingFlags.Public | BindingFlags.Instance; var result = new TTarget(); var targetType = typeof(TTarget); var sourceProperties = source.GetType().GetProperties(publicInstance); foreach (var sourceProperty in sourceProperties) { if (sourceProperty.CanRead) { var targetProperty = targetType.GetProperty(sourceProperty.Name, publicInstance); if (targetProperty != null && sourceProperty.PropertyType == targetProperty.PropertyType) targetProperty.SetValue(sourceProperty.GetValue(source), result); } } return result; } Проблема в таких мапперах заключается в том, что они требуют серьёзного тестирования для разнообразных граничных случаев и нетривиальных преобразований типа. В качестве работающей альтернативы действительно хорошо подходит автомаппер, который уже хорошо протестирован.

Ответ 3



Вот тот же пример для .NET 4 static TTarget Copy(object source) where TTarget : new() { if (source == null) return default(TTarget); const BindingFlags publicInstance = BindingFlags.Public | BindingFlags.Instance; TTarget result = new TTarget(); Type targetType = typeof(TTarget); PropertyInfo[] sourceProperties = source.GetType().GetProperties(publicInstance); foreach (PropertyInfo sourceProperty in sourceProperties) { if (sourceProperty.CanRead) { PropertyInfo targetProperty = targetType.GetProperty(sourceProperty.Name, publicInstance); if (targetProperty != null && sourceProperty.PropertyType == targetProperty.PropertyType) { object[] myArgs = new object[1] { sourceProperty.GetGetMethod().Invoke(source, null) }; targetProperty.GetSetMethod().Invoke(result, myArgs); } } } return result; }

Ответ 4



Вот доработанная версия для .NET 4, теперь копируются и подклассы и конвертируются массивы. Код конечно очень плохо написан. private class MDS_Tools { public static TTarget Copy(object source) where TTarget : new() { if (source == null) return default(TTarget); const BindingFlags publicInstance = BindingFlags.Public | BindingFlags.Instance; TTarget result = new TTarget(); Type targetType = typeof(TTarget); PropertyInfo[] sourceProperties = source.GetType().GetProperties(publicInstance); foreach (PropertyInfo sourceProperty in sourceProperties) { if (sourceProperty.CanRead) { PropertyInfo targetProperty = targetType.GetProperty(sourceProperty.Name, publicInstance); if (targetProperty != null) { MethodInfo smi = sourceProperty.GetGetMethod(); if (sourceProperty.PropertyType == targetProperty.PropertyType) { object[] myArgs = new object[1] { smi.Invoke(source, null) }; targetProperty.GetSetMethod().Invoke(result, myArgs); } else { if (smi.ReturnType.GetInterfaces().Where(t => t.Name == "IEnumerable").FirstOrDefault() != null) { object arrToCopy = Activator.CreateInstance(targetProperty.GetGetMethod().ReturnType); MethodInfo addMeth = arrToCopy.GetType().GetMethod("Add"); IEnumerable enAr = (IEnumerable)smi.Invoke(source, null); if (enAr != null) { foreach (var s in (IEnumerable)smi.Invoke(source, null)) { addMeth.Invoke(arrToCopy, new object[1] { typeof(MDS_Tools).GetMethod("Copy").MakeGenericMethod(((IEnumerable)arrToCopy).AsQueryable().ElementType).Invoke(null, new object[] { s }) }); } object[] myArgs = new object[1] { arrToCopy }; targetProperty.GetSetMethod().Invoke(result, myArgs); } } else { if (smi.ReturnType != typeof(Object)) { object[] myArgs = new object[1] { typeof(MDS_Tools).GetMethod("Copy") .MakeGenericMethod(targetProperty.GetGetMethod().ReturnType) .Invoke(targetProperty, new object[] { smi.Invoke(source, null) }) }; targetProperty.GetSetMethod().Invoke(result, myArgs); } } } } } } return result; } }

Комментариев нет:

Отправить комментарий