2

ディープコピーを実行しようとしているクラスがあります。このクラスのメンバーの1つは、MeshContainerCollectionのインスタンスである「MeshContainers」です。

MeshContainerCollection <>は、List<>から継承するSceneObjectCollection<>クラスから継承します

私が気付いたのは、複製されたオブジェクトが0であるのに対し、ソースオブジェクトはmeshcontainercollection内に1つのアイテムを持っていることです。DeepCopyプロセスをステップ実行すると、MeshContainerCollectionのフィールドを取得しようとしても、何も見つからないことに気付きました。現在、MeshContainerCollectionには直接フィールドがない(継承されたフィールドのみ)ので、それが問題だと思いました。

しかし、私は使用します:

FieldInfo[] fields = type.GetFields(BindingFlags.Public |
        BindingFlags.NonPublic | BindingFlags.Instance);

どの(afaik)もプライベート継承メンバーを返す必要があります。既存のBindingFlagsを調べましたが、継承されたプライベートフィールドを取得するために使用する必要がある別のBindingFlagがあるかどうかを判断できませんでした。

誰かが私が本当に深いコピーを行うことができる方法を教えてもらえますか?

私が使用しているディープコピー方式:

private static object Process(object obj)
{
    if (obj == null)
        return null;
    Type type = obj.GetType();
    if (type.IsValueType || type == typeof(string))
    {
        return obj;
    }
    else if (type.IsArray)
    {
        Type elementType = Type.GetType(
             type.FullName.Replace("[]", string.Empty));
        var array = obj as Array;
        Array copied = Array.CreateInstance(elementType, array.Length);
        for (int i = 0; i < array.Length; i++)
        {
            copied.SetValue(Process(array.GetValue(i)), i);
        }
        return Convert.ChangeType(copied, obj.GetType());
    }
    else if (type.IsClass)
    {
        object toret = FormatterServices.GetUninitializedObject(obj.GetType());
        FieldInfo[] fields = type.GetFields(BindingFlags.Public |
                    BindingFlags.NonPublic | BindingFlags.Instance);
        foreach (FieldInfo field in fields)
        {
            object fieldValue = field.GetValue(obj);
            if (fieldValue == null)
                continue;
            field.SetValue(toret, Process(fieldValue));
        }

        return toret;
    }
    else
        throw new ArgumentException("Unknown type");
}

編集1:私はこれをシリアル化ではなくリフレクションによって行うことを好みます。

4

2 に答える 2

1

GetFields のドキュメントに記載されているように、

基本クラスのプライベート フィールドは返されません。

代わりに次の方法を試してください。

public static IEnumerable<FieldInfo> GetAllFields(this Type type)
{
    IEnumerable<FieldInfo> fields = type.GetFields(
        BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

    if (type.BaseType == null)
        return fields;
    else
        return GetAllFields(baseType).Concat(fields);
}

(すべての列挙型と連結を避けるために書き直したくなるかもしれませんが、アイデアは得られます)

于 2012-06-19T12:36:29.060 に答える
0

これを実現する方法の 1 つは、オブジェクトをシリアル化してから逆シリアル化することです。同じことを行う関数を作成します。参考までに、[Serializable]このためにクラスをマークする必要があります。

同じことを行うライブラリがいくつかあります.コピー可能はそれらの1つです.ディープコピーするときに処理するにはエッジ条件が多すぎるため、このライブラリを構築するのではなく、ホイールを再発明しようとしないことをお勧めします..作者にもパッチを提出できるかもしれません..

于 2012-06-19T12:30:41.433 に答える