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;
}

しかし、私の実際のプログラムではそうではありません。実際のプログラムのクラスの宣言は長いので、ここでは投稿しません。何が問題なのでしょう?

4

3 に答える 3

3

私はずっと前に同じ問題を抱えていました。たくさんのグーグルの後、私にとって唯一の本当の解決策は、それをシリアル化して逆シリアル化することでした。これは悪い解決策ではなく、パフォーマンスが少し低下するだけです。次のようにしてください。

このタグをクラスに追加します。

[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);
}
于 2012-04-22T14:36:02.097 に答える
2

浅いクローンが必要な場合は、単に。を使用しますObject.MemberwiseClone。ディープクローンが必要な場合は、オブジェクトをシリアル化してから逆シリアル化します(たとえば、BinaryFormatterまたはを使用DataContractSerializer)。これにより、サイクルや相互参照などの問題が処理されます。

于 2012-04-23T07:33:49.683 に答える
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;
}
于 2012-04-22T15:19:36.060 に答える