使用C#reflection

时间:2017-05-20 00:15:25

标签: c# entity-framework reflection setvalue

我的任务是编写针对现有数据库的例程。这个数据库有几个具有相同结构但名称不同的表(我没有设计这个,请不要建议更改数据库设计)。我在EF中写这个,模型是数据库优先创建的。

我能想到的最佳选择是创建一个具有完全相同属性的类,并创建一个可以接受泛型类型的例程,将数据从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;
    }

无论我尝试什么,我总是得到:

  

类型&#39; System.Reflection.TargetException&#39;的例外情况发生在mscorlib.dll但未在用户代码中处理。附加信息:对象与目标类型不匹配。

我无法弄清楚我错过了什么。

  1. 我可能缺少什么?
  2. 我是以错误的方式来做这件事的吗?如果是这样的话,在这些条件下做什么是正确的做法?
  3. 感谢任何帮助,谢谢!

1 个答案:

答案 0 :(得分:1)

您对GetProperties()的调用会获得一系列PropertyInfo个对象,这些对象将应用于该特定类型。因此,当您调用GetValue()时,您正试图从错误类型的对象中获取值。

即。用于获取T2对象的类型PropertyInfoGenericSampleClass,但您传递给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()约束添加到泛型类型参数以要求目标类型具有无参数构造,因此您实际上可以使用表达式new T2()来创建对象的新实例。