Как на 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;
Но так слишком много писать, хотелось бы по короче и побыстрее.
Ответы-ссылки тут не приветствуются, но в этом случае без ссылки никак: AutoMapper.
Package Manager:
Install-Package AutoMapper
C#:
Mapper.CreateMap<A, Result>();
Mapper.CreateMap<B, Result>();
var a = new A() { First = "1", Second = "2" };
var b = new B() { Third = "3", Four = "4" };
var res = Mapper.Map<Result>(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<Result>(a);
Mapper.DynamicMap(b, res);
В таких случаях обычно используют рефлексию. Простой пример копирования публичных свойств с идентичными типами:
static TTarget Copy<TTarget>(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;
}
Проблема в таких мапперах заключается в том, что они требуют серьёзного тестирования для разнообразных граничных случаев и нетривиальных преобразований типа. В качестве работающей альтернативы действительно хорошо подходит автомаппер, который уже хорошо протестирован.
Вот тот же пример для .NET 4
static TTarget Copy<TTarget>(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;
}
Вот доработанная версия для .NET 4, теперь копируются и подклассы и конвертируются массивы. Код конечно очень плохо написан.
private class MDS_Tools {
public static TTarget Copy<TTarget>(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;
}
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Ищу варианты для получения видео с облачного хранилищаПришла мысль, что может как то можно получить ссылку на видео с гугл диска в приложение
Часто бывает так, что когда в коде создаешь пару из #region #endregion то после перезапуска VS, или даже просто запуска приложения для отладки (и по другим...