【问题标题】:C# - How to copy/create an object as a decendentC# - 如何复制/创建一个对象作为后代
【发布时间】:2010-03-05 22:07:36
【问题描述】:

这更容易用一个例子来解释。鉴于这两个类:

public class MyClassA
{
    public String Property_A { get; set; }
    public String Property_B { get; set; }
    public String Property_C { get; set; }
    public String Property_D { get; set; }
    ...
    public String Property_Y { get; set; }
}

public class MyClassB: MyClassA
{
    public String Property_Z { get; set; }
}

假设我已经完全创建了 MyClassA 的实例(填充了 A - Y 的所有属性)。然后我需要创建一个 MyClassB 的实例,它与我的 MyClassA 实例完全相同,但填充了 Property_Z(当然是自定义值)。我该怎么做?

这样做不起作用(抛出和无效的强制转换异常):

MyClassB myInstanceB = (myClassB) myInstanceA;
myInstance.Property_Z = myCustomValue;

自从我的 C++ 时代以来,我就不需要做这样的事情了,我被难住了。

有什么想法吗?


更新:我找到了解决我如何创建实例的问题的方法。它在下面。我没有将其标记为答案,因为它不完全符合我的问题。

【问题讨论】:

    标签: c# .net-3.5 inheritance


    【解决方案1】:

    您创建的实例是MyClassA。那是它的运行时类型,而不是MyClassB。您不能在运行时将MyClassA 实例转换为MyClassB,因为MyClassB 是比MyClassA 更具体的类型。

    您需要创建一个全新的MyClassB 实例。清理它的一种方法是创建一个采用MyClassA 的构造函数,例如

    public class MyClassB : MyClassA
    {
        public MyClassB(MyClassA a, string z)
        {
            this.PropertyA = a.PropertyA;
            this.PropertyB = a.PropertyB;
            // etc.
            this.PropertyZ = z;
        }
    
        public string PropertyZ { get; set; }
    }
    

    【讨论】:

    • 我没有说出来,但我希望避免将所有项目从一个实例复制到另一个实例。
    • @Vaccano:如果你发现自己不得不到处这样做,那么我会重新考虑你的设计;但是,如果您迫切需要加快流程,那么您可以使用反射或基于反射的映射器,例如 AutoMapper - 只要知道您保存编码的时间将被程序中增加的执行时间所抵消(多少时间取决于你多久做一次)。
    • 是的,我也不想减慢执行速度。通过更改我设置 myInstanceA 以使用类型参数的方式,我找到了一个折衷方案(请参阅我对这个问题的回答)。我没有像我希望的那样将 myInstanceA 转换为 MyClassB,但它可以工作。 (我不会将我的答案设置为“答案”,因为它与我提出的问题不太匹配。)
    【解决方案2】:

    您可以使用反射复制基类属性,如here 所示。

     public void Update(MyObject o)
        {
            MyObject copyObject = ...
            Type type = o.GetType();
            while (type != null)
            {
                UpdateForType(type, o, copyObject);
                type = type.BaseType;
            }
        }
    
    
        private static void UpdateForType(Type type, MyObject source, MyObject destination)
        {
            FieldInfo[] myObjectFields = type.GetFields(
                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    
            foreach (FieldInfo fi in myObjectFields)
            {
                fi.SetValue(destination, fi.GetValue(source));
            }
        }
    

    【讨论】:

      【解决方案3】:

      直截了当的答案:

      public class MyClassA 
      { 
          public String Property_A { get; set; } 
          public String Property_B { get; set; } 
          public String Property_C { get; set; } 
          public String Property_D { get; set; } 
          ... 
          public String Property_Y { get; set; } 
      } 
      
      public class MyClassB: MyClassA 
      { 
          public MyClassB(MyClassA copy)
          {
              Property_A = copy.PropertyA;
              Property_B = copy.PropertyB;
              ...
          }
          public String Property_Z { get; set; } 
      } 
      

      像这样使用它:

      MyClassB o = new MyClassB(instanceOfMyClassA);
      o.Property_Z = whatever;
      

      【讨论】:

        【解决方案4】:

        听起来您正在寻找免费的复制构造函数。 C# 不提供 (http://msdn.microsoft.com/en-us/library/ms173116%28VS.80%29.aspx) 但您可以使用 Object.MemberwiseClone 或 BinaryFormatter 序列化程序 (http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx) 轻松完成。请注意您需要浅拷贝还是深拷贝。

        【讨论】:

          【解决方案5】:

          您可以定义从 MyClassA 到 MyClassB 的显式或隐式转换并使用您提供的语法。

          public class MyClassB : MyClassA
          {
              public String Property_Z { get; set; }
          
              public static explicit operator MyClassB(MyClassA a)
              {
                  MyClassB b = new MyClassB();
                  b.Property_A = a.Property_A;
                  /* ... */
                  b.Property_Y = a.Property_Y;
                  return b;
              }
          }
          

          【讨论】:

            【解决方案6】:

            怎么样:

            1. 创建一个实现 IClonable 并具有所有字符串属性 A 到 D 和 Z 的基类。
            2. 为 MyClassA 创建此类的实例。
            3. 通过克隆 MyClassA 创建 MyClassB 的实例。
            4. 在 MyClassB 中设置属性 Z。

            【讨论】:

              【解决方案7】:

              这是我最终做的:

              我创建了创建和设置所有使用类型参数的属性 (A-Y) 的方法。它看起来像这样:

              public T MakeAMyClass<T>(AnotherClass 
              where T: MyClassA : new()
              {
                 T returnValue = new T();
                 T.Property_A = somethingToSetFrom.MakeAPropertyA();
                 // Fill in the rest of the properties
              }
              

              因为类型参数可以是从约束派生的类型,所以我能够传入 MyClassB 对象并以与 myClassA 相同的方式生成它们。

              然后我可以根据需要制作任何一个。

              MyClassA myInstanceA = MakeAMyClass<MyClassA>(somethingToSetFrom);
              MyClassB myInstanceB = MakeAMyClass<MyClassB>(somethingToSetFrom);
              myInstanceB.Property_Z = someotherValue;
              

              这让我不必创建一个方法来将所有属性从 MyClassA 复制到 MyClassB。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2021-04-05
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多