2012-04-22 90 views
1

我想克隆派生類的實例,但不知何故它不能正常工作。克隆方法是:爲什麼克隆不起作用?

public static T CloneFieldsAndProperties<T>(T input) 
{ 
    T result = (T)Activator.CreateInstance(typeof(T)); 
    PropertyInfo[] listOfProps = typeof(T).GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.CreateInstance); 
    FieldInfo[] listOfFields = typeof(T).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.CreateInstance); 
    foreach (PropertyInfo prop in listOfProps) prop.SetValue(result, prop.GetValue(input, null), null); 
    foreach (FieldInfo field in listOfFields) field.SetValue(result, field.GetValue(input)); 
    return result; 
} 

正如你所看到的,我加入了很多BindingFlags,因爲它不工作。但無濟於事。

做一個簡單的例子工作:

MyclassA1 a1 = new MyclassA1(); 
MyclassA a = CloneFieldsAndProperties(a1); 
if (a is MyclassA1) Text = "Works"; 

其中:

class MyclassA 
{ 
    public int i; 
} 

class MyclassA1 : MyclassA 
{ 
    public int i1; 
} 

但在我真正的程序沒有。真正的課程的類聲明很長,所以我不會在這裏發佈它們。可能是什麼問題?

+1

如果它在這個簡單的例子中起作用,那麼問題可能出在你說你忽略的代碼的某個地方? – 2012-04-22 14:05:48

+0

你應該使用'Object.MemberwiseClone'。 – 2012-04-22 14:06:53

+0

@EliArbel只創建一個淺拷貝。我的情況不好。但是,謝謝。 – ispiro 2012-04-22 14:09:48

回答

2

如果你需要一個淺克隆,簡單地使用Object.MemberwiseClone。如果您需要深度克隆,請序列化並反序列化您的對象(例如,使用BinaryFormatterDataContractSerializer)。這將處理週期和交叉引用等問題。

3

很久以前我有同樣的問題。對於我來說,唯一真正的解決方案是大量使用Google進行序列化和反序列化。這不是一個壞的解決方案,你失去唯一的性能一點點,只是做這樣的:

添加此標記到類:

[Serializable()] 
public class a 
{ 

} 

然後你就可以創建這樣一個功能:

public object Clone() 
{ 
    IO.MemoryStream mem = new IO.MemoryStream(); 
    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter form = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 
    form.Serialize(mem, this); 
    mem.Position = 0; 
    return form.Deserialize(mem); 
} 
0

這將工作和可能比序列化方法更快:

代碼:

using System; 

namespace Cloning 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Derived d = new Derived() { property = 1, field = 2, derivedProperty = 3, derivedField = 4 }; 
      Base b = new Derived(d); 

      // Change things in the derived class. 
      d.property = 5; 
      d.field = 6; 
      d.derivedProperty = 7; 
      d.derivedField = 8; 

      // Output the copy so you know it's not shallow. 
      Console.WriteLine((b as Derived).property); 
      Console.WriteLine((b as Derived).field); 
      Console.WriteLine((b as Derived).derivedProperty); 
      Console.WriteLine((b as Derived).derivedField); 

      Console.ReadLine(); 
     } 

     class Base 
     { 
      public int property { get; set; } 
      public int field; 
     } 

     class Derived : Base 
     { 
      public Derived() { } 

      public Derived(Derived d) 
      { 
       // Perform the deep copy here. 
       // Using reflection should work, but explicitly stating them definitely 
       // will, and it's not like it's not all known until runtime. 
       this.property = d.property; 
       this.field = d.field; 
       this.derivedProperty = d.derivedProperty; 
       this.derivedField = d.derivedField; 
      } 

      public int derivedProperty { get; set; } 
      public int derivedField; 
     } 

    } 
} 

測試:

http://goo.gl/pQnAL

輸出:

1 
2 
3 
4 

評論:

我真的想象,這將超過只是一個微不足道的情況下,但也許不行:

public static T CloneFieldsAndProperties<T>(T input) 
{ 
    T result = (T)Activator.CreateInstance(input.GetType()); 

    PropertyInfo[] properties = input.GetType().GetProperties(); 
    FieldInfo[] fields = input.GetType().GetFields(); 

    foreach (PropertyInfo property in properties) 
     property.SetValue(result, property.GetValue(input, null), null); 
    foreach (FieldInfo field in fields) 
     field.SetValue(result, field.GetValue(input)); 

    return result; 
}