C# 使用C反射将一种类型的对象的值复制到另一种类型的对象
我的任务是针对现有数据库编写一个例程。这个数据库有几个表具有相同的结构,但不同的名称我没有设计这个,请不要建议更改数据库设计。我在EF中写这篇文章,模型是首先在数据库中创建的 对于这种情况,我能想到的最佳选择是创建一个具有完全相同属性的类,并创建一个可以接受泛型类型的例程,以将数据从EF模型复制到泛型模型 我的模型:C# 使用C反射将一种类型的对象的值复制到另一种类型的对象,c#,entity-framework,reflection,setvalue,C#,Entity Framework,Reflection,Setvalue,我的任务是针对现有数据库编写一个例程。这个数据库有几个表具有相同的结构,但不同的名称我没有设计这个,请不要建议更改数据库设计。我在EF中写这篇文章,模型是首先在数据库中创建的 对于这种情况,我能想到的最佳选择是创建一个具有完全相同属性的类,并创建一个可以接受泛型类型的例程,以将数据从EF模型复制到泛型模型 我的模型: // Sample EF database-first created model namespace SampleDataModel.Models {
// Sample EF database-first created model
namespace SampleDataModel.Models
{
using System;
using System.Collections.Generic;
public partial class SampleClassFlavorOne
{
public int Id {get; set;}
public string PropertyOne {get; set;}
public string Property2 {get; set;}
public DateTime Property3 {get; set;}
}
}
// Sample of generic class I created
public class GenericSampleClass{
public int Id {get; set;}
public string PropertyOne {get; set;}
public string Property2 {get; set;}
public DateTime Property3 {get; set;}
}
我的日常工作:
private static void CopyFlavorToGenericList<T1, T2>(List<T1> fromList, List<T2> toList){
foreach (var t in fromList)
{
//(As you can see, I have tried entering the foreach loop a both ways
//foreach (var p in typeof(T1).GetProperties())
foreach (var p in typeof(T2).GetProperties())
{
if (p != null && p.CanWrite)
{
dynamic newObject = null;
p.SetValue((T2)newObject, p.GetValue(t, null), null);
}
}
toList.Add(toObject);
}
}
执行例行程序:
switch (flavor){
case "FlavorOne":
List<SampleClassFlavorOne> _baseFlavor = db.SampleClassFlavorOne.ToList();
List<GenericSampleClass> _genericFlavor = new List<GenericSampleClass>();
CopyFlavorToGenericList<SampleClassFlavorOne, GenericSampleClass>(_baseFlavor, _genericFlavor);
break;
}
无论我尝试什么,我总是得到:
mscorlib.dll中发生“System.Reflection.TargetException”类型的异常,但未在用户代码中处理。其他信息:对象与目标类型不匹配
我不知道我错过了什么
我会错过什么?
我走错方向了吗?如果是这样,在这些条件下,我想做的事情的正确方法是什么?
感谢您的帮助,谢谢 对GetProperties的调用将获取应用于该特定类型的PropertyInfo对象数组。因此,当您调用GetValue时,您试图从错误类型的对象获取值
也就是说,T2,用于获取PropertyInfo对象的类型,是GenericSampleClass,但是传递给GetValue方法的对象的类型是SampleClassFlavorOne。在您的替代方案中,从T1获取属性,您也有同样的问题,但是使用SetValue方法,在理论上传递…但不是真的,请参见注释:下面是GenericSampleClass类型的对象,当PropertyInfo对象来自SampleClassFlavorOne类型时
要正确执行此操作,需要从这两个类中获取PropertyInfo对象,并将它们与适当类型的对象一起使用。例如:
private static void CopyFlavorToGenericList<T1, T2>(List<T1> fromList, List<T2> toList) where T2 : new()
{
var map = from p1 in typeof(T1).GetProperties()
join p2 in typeof(T2).GetProperties()
on p1.Name equals p2.Name
select new { From = p1, To = p2 };
foreach (var t in fromList)
{
T2 toObject = new T2();
foreach (var copyItem in map)
{
if (copyItem.To.CanWrite)
{
copyItem.To.SetValue(toObject, copyItem.From.GetValue(t));
}
}
toList.Add(toObject);
}
}
注意:您在如何创建新对象方面也有问题。我甚至不知道你是什么意思,像那样使用dynamic,但它不会起作用。您只是将null作为目标对象的值传递,这没有任何用处
您需要能够根据需要创建目标对象的实例,在泛型方法中实现这一点的方法是向泛型类型参数添加新约束,以要求目标类型具有无参数构造,因此,您实际上可以使用表达式new T2来创建对象的新实例。谢谢您,彼得!特别是,感谢您不仅提供了代码,而且还提供了出色的解释!我完全理解我遇到的问题,以及我的决心。我必须在你的字条上为自己辩护一点;这是我在这个网站上看到的尝试一些解决方案的最后努力的一部分——我想知道我自己该怎么做。我不知道如何使t2toobject=newt2;工作,你的建议添加T2:new是完美的!再次感谢+还有一个关于这个问题的问题:我知道反射本身就是一种性能上的冲击。创建变量映射的需要是否会增加对性能的影响?看看这个解决方案,我几乎想说我只使用了一次反射,而不是在我的fromList的每个对象上,因此实际上减少了这个命中率。我说的对吗?@Matt:是的,创建一次地图对象比为列表中的每个对象创建一次要好。调用GetValue和SetValue方法仍有成本,这比直接访问属性要慢。与其他技术相比,反射速度较慢,但这可能是问题,也可能不是问题,这取决于您需要执行此代码的频率。如果速度成了一个问题,您可以通过构建表达式对象来访问可以编译的属性,并使用字典在对复制方法的调用中缓存这些属性来改善问题。