使用 C# 反射将一种类型的对象的值复制到另一种类型的对象
Copy values of an object of one type to an object of another using C# reflection
我的任务是针对现有数据库编写例程。这个数据库有几个结构相同,但名称不同的表(我没有设计这个,请不要建议数据库设计更改)。我在 EF 中写这个,模型是数据库优先创建的。
对于这种情况,我能想到的最佳选择是创建一个具有完全相同属性的 class,并创建一个可以接受泛型类型的例程,以将数据从 EF 模型复制到泛型模型。
我的模特:
// 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;
}
无论我尝试什么,我总是得到:
An exception of type 'System.Reflection.TargetException' occurred in mscorlib.dll but was not handled in user code. Additional information: Object does not match target type.
我不知道我错过了什么。
- 我可能遗漏了什么?
- 我是不是走错了路?如果是这样,在这些条件下做我想做的事情的正确方法是什么?
感谢任何帮助,谢谢!
您对 GetProperties()
的调用会得到一个 PropertyInfo
对象数组,这些对象 应用于特定类型 。因此,当您调用 GetValue()
时,您正试图从错误类型的对象中获取值。
即T2
,用来获取PropertyInfo
对象的类型是GenericSampleClass
,但是你传递给GetValue()
方法的对象类型是SampleClassFlavorOne
。在你的替代方案中,从 T1
获取属性,你有同样的问题,但是使用 SetValue()
方法,传递(理论上......但不是真的,参见下面的 "Note:")一个对象类型 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()
约束添加到泛型类型参数以要求目标类型具有无参数构造,因此您实际上可以使用表达式 new T2()
创建对象的新实例。
我的任务是针对现有数据库编写例程。这个数据库有几个结构相同,但名称不同的表(我没有设计这个,请不要建议数据库设计更改)。我在 EF 中写这个,模型是数据库优先创建的。
对于这种情况,我能想到的最佳选择是创建一个具有完全相同属性的 class,并创建一个可以接受泛型类型的例程,以将数据从 EF 模型复制到泛型模型。
我的模特:
// 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;
}
无论我尝试什么,我总是得到:
An exception of type 'System.Reflection.TargetException' occurred in mscorlib.dll but was not handled in user code. Additional information: Object does not match target type.
我不知道我错过了什么。
- 我可能遗漏了什么?
- 我是不是走错了路?如果是这样,在这些条件下做我想做的事情的正确方法是什么?
感谢任何帮助,谢谢!
您对 GetProperties()
的调用会得到一个 PropertyInfo
对象数组,这些对象 应用于特定类型 。因此,当您调用 GetValue()
时,您正试图从错误类型的对象中获取值。
即T2
,用来获取PropertyInfo
对象的类型是GenericSampleClass
,但是你传递给GetValue()
方法的对象类型是SampleClassFlavorOne
。在你的替代方案中,从 T1
获取属性,你有同样的问题,但是使用 SetValue()
方法,传递(理论上......但不是真的,参见下面的 "Note:")一个对象类型 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()
约束添加到泛型类型参数以要求目标类型具有无参数构造,因此您实际上可以使用表达式 new T2()
创建对象的新实例。