代码之家  ›  专栏  ›  技术社区  ›  the_drow

将对象复制到C中的“this”对象#

  •  3
  • the_drow  · 技术社区  · 15 年前

    我有一个特定的hirerchy类,它需要能够将所有公共属性从一个对象复制到另一个对象。
    可能会有所不同

    例子:

    class Base
    {
      // Common properties/methods...
      public void Copy<T>(T data) where T : Base
      {
         // ...
      }
    }
    
    class D1 : Base
    {
      public int ID
      {
        get;
        set;
      }
    }
    
    class D2 : Base
    {
      public string Name
      {
        get;
        set;
      }
    }
    

    通过谷歌我了解到了这些方法:

    • 使用反射
    • 序列化

    它们要么非常复杂,要么非常缓慢,有时两者兼而有之。
    我错过什么了吗?有没有其他方法可以获取原始数据 this 指针?

    编辑:
    我来做牧师。
    T是调用类的类型。例如,如果它被D1调用,T将始终是D1。

    我错过什么了吗?
    Base data 作为参数?

    5 回复  |  直到 15 年前
        1
  •  1
  •   Niels van der Rest    15 年前

    Copy 中的方法 Base 类只能访问中定义的属性 底座 班级。你呢

    但你呢 复制子类中的属性而不使用反射之类的东西。但是即使使用反射,您也需要一些关于不同子类之间属性映射的知识,比如复制 ID 属性到 Name .

    因此,您需要为每个(允许的)子类转换编写单独的实现。

    public interface IBaseCopier<TFrom, TTo> where TFrom : Base, TTo : Base
    {
      void Copy(TFrom from, TTo to);
    }
    
    public class D1ToD2Copier : IBaseCopier<D1, D2>
    {
      public void Copy(D1 from, D2 to)
      {
        // Copy properties from the D1 instance to the D2 instance.
      }
    }
    

    ICopier<TFrom, TTo> 工厂类中的实现。此类将根据类型参数查找复印机的实现。如果某个类型组合没有复印机,即不支持转换,工厂应该抛出异常。

    public class CopierFactory
    {
      public ICopier<TFrom, TTo> Create<TFrom, TTo>() where TFrom : Base, TTo : Base
      {
        // Look up the ICopier implementation for the given types.
      }
    }
    

    编辑

    你可以用 MemberwiseClone 方法创建对象的副本。

    public class Base
    {
      public static T Copy<T>(T data) where T : Base
      {
        return data.MemberwiseClone() as T;
      }
    }
    

    ICloneable interface .

    注: 你应该意识到你不能克隆一个 D1 实例到 D2 实例。那就像把羊克隆成马一样。

        2
  •  6
  •   Matt Mitchell    15 年前

    您所缺少的是,您要求编译器知道T可能是D1和D2类型之一,而您所说的只是T是一个基。怎么可能知道你的对象是什么属性甚至类型,因为这些信息只有在运行时才知道。即使你 能够 foreach (PropertyInfo in this.Properties) 反射,只是更漂亮的语法)。它不知道什么属性是公共的,直到它知道它处理的是什么类型,并且你说“在运行时之前我不会告诉你”,所以答案是“我必须看运行时”,即反射。

    例如,

    • 炮弹。炮弹和弹药
    • 加利福尼亚州和MyBrokenEngine州
    • 扬声器。音量和MassiveCrater。音量

    等等等等。

        3
  •  2
  •   Dr Herbie    15 年前

    您可以使用架构更改来解决这个问题,并使用“PropertyBag”来存储每个类的属性。

    PropertyBag本质上是 Dictionary<string, object> 你可以给一段数据起个名字,然后把它加到包里。缺点是一切都会被抛到一边 object

    public int MyProperty
    {
        get
        {
            return (int)_propertyBag["MyProperty"];
        }
        set
        {
            if(_propertyBag.Keys.Contains("MyProperty"))
            {
              _propertyBag["MyProperty"] = value;
            }
            else
            {
              _propertyBag.Add("MyProperty", value);
            }
        }
    }
    

    所以现在要聚合派生类的所有属性,可以公开它们的“raw”PropertyBag并遍历它。

    就像我之前说过的,propertyBag不是类型安全的,所以如果层次结构中有两个类具有相同的属性名,但类型不同,那么您就有麻烦了。

    编辑:如果您关心性能,那么您将不得不以多种方式实现这个功能,并对不同的实现进行性能测试——老实说,PropertyBag是否真的比使用反射更快。

        4
  •  1
  •   bpeterson76    12 年前

    我认为copy方法应该由派生类D1、D2继承,它们负责将自己的属性复制到其他类型中。

        5
  •  0
  •   Francisco Soto    15 年前

    我要做的是创建一个 extension method

    namespace ExtensionMethods
    {
        public static class MyExtensions
        {
            public static int CopyTo<T>(this Base source, ref T dest)
            {
              // Use reflection to cycle public properties and if you find equally named ones, copy them.
            }
        }   
    }
    

    然后你可以在你的对象中调用它,比如:

      source.CopyTo<ClassType>(ref this);
    

    我没有测试,所以不确定它是否能像描述的那样工作。在我所从事的一个大项目中,我做了一些类似于将数据行转换成实体的事情。

    推荐文章