【问题标题】:Copy values of an object of one type to an object of another using C# reflection使用 C# 反射将一种类型的对象的值复制到另一种类型的对象
【发布时间】:2017-05-20 00:15:24
【问题描述】:

我的任务是针对现有数据库编写例程。这个数据库有几个表结构相同,但名称不同(我没有设计这个,请不要建议更改数据库设计)。我在 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;
    }

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

“System.Reflection.TargetException”类型的异常发生在 mscorlib.dll 中,但未在用户代码中处理。附加信息:对象与目标类型不匹配。

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

  1. 我可能缺少什么?
  2. 我是不是走错了路?如果是这样,在这些条件下,做我想做的事情的正确方法是什么?

任何帮助表示赞赏,谢谢!

【问题讨论】:

    标签: c# entity-framework reflection setvalue


    【解决方案1】:

    您对GetProperties() 的调用将获得一个PropertyInfo 对象数组,这些对象应用于该特定类型。因此,当您调用GetValue() 时,您是在尝试从错误类型的对象中获取值。

    T2,用于获取PropertyInfo 对象的类型是GenericSampleClass,但是您传递给GetValue() 方法的对象类型是SampleClassFlavorOne。在您的替代方案中,从T1 获取属性,您有同样的问题,但是使用SetValue() 方法,传递(理论上......但不是真的,请参阅下面的“注意:”)GenericSampleClass 类型的对象,当PropertyInfo 对象来自SampleClassFlavorOne 类型时。

    要正确执行此操作,您需要从 both 类中获取 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() 来创建对象的新实例。

    【讨论】:

    • 谢谢彼得!特别感谢您不仅提供代码,还提供了很好的解释!我完全理解我遇到的问题以及解决方法。在您的笔记中,我确实必须为自己辩护一点;这是尝试我在这个网站上看到的一些解决方案的最后努力的一部分——我想知道这应该如何自己工作。我不知道如何使T2 toObject = new T2(); 工作,您添加where T2 : new() 的建议非常完美!再次感谢! +1 并回答。
    • 关于这个主题的另一个问题:我知道反射本身有点影响性能。是否需要创建变量map 会增加对性能的影响?看着解决方案,我几乎想说我正在使用一次反射(而不是在我的 fromList 的每个对象上),因此实际上正在减少这种命中。我说的对吗?
    • @Matt:是的,创建一次map 对象比为列表中的每个对象都创建一次要好。调用GetValue()SetValue() 方法仍然有成本,这比直接访问属性要慢。与其他技术相比,反射速度较慢,但​​这可能是也可能不是问题,具体取决于您需要执行此代码的频率。如果速度成为问题,您可以通过构建Expression 对象来访问属性(可以编译)并使用字典在对复制方法的调用中缓存它们来改进问题。
    猜你喜欢
    • 2016-12-13
    • 1970-01-01
    • 2012-01-10
    • 2015-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-11
    • 1970-01-01
    相关资源
    最近更新 更多