这是一个学术问题比什么都重要......我知道有更多实用的方法可以让发展明智......
假设您有以下代码:
public MyObject1 AssignTest(MyObject1 obj1,MyObject2 obj2) {
}
MyObject1和MyObject2具有完全相同的属性。是否可以自动将MyObject1中指定的所有值分配给MyObject2?而不是以声明方式进行并分配值(即MyObject1.Property1 = MyObject2.Property1等)
答案 0 :(得分:6)
ValueInjector或AutoMapper等映射库对这种功能非常有帮助。
使用AutoMapper,您可以使用类似
的内容创建映射Mapper.CreateMap<MyObject1,MyObject2>();
它有许多默认约定,其中一个默认约定会复制具有相同类型/名称的属性。
然后实际做这样的映射
var myObject2 = Mapper.Map<MyObject1,MyObject2>(myObject1);
当然,你也可以通过反射轻松完成这项工作,但是对于像这样的库,有人已经考虑添加各种方便的映射功能,以及完成性能调整。例如,AutoMapper使用IL生成来读取值而不是反射,因此重复映射事物的速度要快得多(非常适合映射大量事物)
答案 1 :(得分:5)
实现这一目标的一种可能性(例如,为了创建自己的自动化程序或理解它基本上如何工作)将是使用(如已建议的)Reflection。代码可能如下所示:
// TODO: error handling
// Test classes
public class A
{
public string Name { get; set; }
public int Count;
}
public class B
{
public string Name { get; set; }
public int Count;
}
// copy routine
public B CopyAToB(A a)
{
B b = new B();
// copy fields
var typeOfA = a.GetType();
var typeOfB = b.GetType();
foreach (var fieldOfA in typeOfA.GetFields())
{
var fieldOfB = typeOfB.GetField(fieldOfA.Name);
fieldOfB.SetValue(b, fieldOfA.GetValue(a));
}
// copy properties
foreach (var propertyOfA in typeOfA.GetProperties())
{
var propertyOfB = typeOfB.GetProperty(propertyOfA.Name);
propertyOfB.SetValue(b, propertyOfA.GetValue(a));
}
return b;
}
该功能可以这样使用:
var a = new A
{
Name = "a",
Count = 1
};
var b = CopyAToB(a);
Console.Out.WriteLine(string.Format("{0} - {1}", b.Name, b.Count));
输出结果为:
a - 1
请注意,反射的使用需要付出代价 - 它会降低性能。使用反射,您可以访问私有和公共对象成员。例如,这可以从Visual Studio中使用,以创建测试访问器对象,以便访问所有测试对象成员。
请查看现有的自动化程序(请参阅链接的其他答案)并使用它们而不是重新发明轮 - 现有库已针对速度进行了优化,经过全面测试并且非常使用舒适。这样您就可以最大限度地减少代码中的错误。
答案 2 :(得分:1)
有很多工具可以做到这一点。以服务堆栈中的“TranslateTo”例程为例。他们有出色的自动映射(https://github.com/ServiceStack/ServiceStack/wiki/Auto-mapping)。
使用此功能,您只需要:
obj2 = obj1.TranslateTo<MyObject2>();
简单而优雅!
如果您对其他一些类似主题的引用感兴趣:
答案 3 :(得分:1)
从@pasty的accepted answer开始,我为此创建了通用方法。
public static TDest MapSourceToDest<TSource, TDest>(TSource source)
where TSource : class//We are not creating an instance of source, no need to restrict parameterless constructor
where TDest : class, new()//We are creating an instance of destination, parameterless constructor is needed
{
if(source == null)
return null;
TDest destination = new TDest();
var typeOfSource = source.GetType();
var typeOfDestination = destination.GetType();
foreach(var fieldOfSource in typeOfSource.GetFields())
{
var fieldOfDestination = typeOfDestination.GetField(fieldOfSource.Name);
if(fieldOfDestination != null)
{
try
{ fieldOfDestination.SetValue(destination, fieldOfSource.GetValue(source)); }
catch(ArgumentException) { }//If datatype is mismatch, skip the mapping
}
}
foreach(var propertyOfSource in typeOfSource.GetProperties())
{
var propertyOfDestination = typeOfDestination.GetProperty(propertyOfSource.Name);
if(propertyOfDestination != null)
{
try
{ propertyOfDestination.SetValue(destination, propertyOfSource.GetValue(source)); }
catch(ArgumentException) { }//If datatype is mismatch, skip the mapping
}
}
return destination;
}
可能需要更改通用类型的过滤器;但是其他所有类型都可以跨任何类型工作。为fieldOfDestination
和propertyOfDestination
添加空检查,以防万一成员丢失;这增加了一点灵活性。
答案 4 :(得分:0)
AutoMapper是另一个很好用的工具http://automapper.codeplex.com/
您可以使用以下内容从一个对象映射到另一个对象:
Mapper.CreateMap<MyClass, MyDTO>();
var myDTO = Mapper.Map<MyClass, MyDTO>(myClass);
答案 5 :(得分:0)
我改进并概括了@keenthinker 的响应,它始终适用于任何类型的对象。
调用静态方法并传递地图类和对象
var result = SimpleMapper.Map<FromModel, ToModel>(data);
实现:
public static class SimpleMapper
{
public static T Map<F, T>(F from)
{
// inicialize return object
T b = (T)Activator.CreateInstance(typeof(T));
// copy fields
Type typeOfA = typeof(F);
Type typeOfB = typeof(T);
foreach (var fieldOfA in typeOfA.GetFields())
{
var fieldOfB = typeOfB.GetField(fieldOfA.Name);
fieldOfB.SetValue(b, fieldOfA.GetValue(from));
}
// copy properties
foreach (var propertyOfA in typeOfA.GetProperties())
{
var propertyOfB = typeOfB.GetProperty(propertyOfA.Name);
propertyOfB.SetValue(b, propertyOfA.GetValue(from));
}
return (T)b;
}
}
答案 6 :(得分:0)
这个问题很老了,但使用 JsonConvert 会更快吗?
MyObject2 obj2 = JsonConvert.DeserializeObject<MyObject2>(JsonConvert.SerializeObject(obj1));