16

この質問では、これが可能かどうか、そしてどのように可能かを知りたいと思います。この手法は非常に悪い習慣に思えますが、私が使用しているAPI(UnityEditor)はこのようなことをしているようで、興味があります。

同じオブジェクトへの複数の参照がある場合、以前のすべての参照が新しいオブジェクトを指すように、同じメモリスロットに新しいオブジェクトをインスタンス化することは可能ですか?

そのための唯一の実行可能な方法は、アンマネージC++を使用することであることがわかりました。基本的に、次のことが起こっています。

// Original prefab
GameObject prefab = x;
prefab.tag = "Untagged";

// A copy of the original prefab
GameObject prefabCopy = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
prefabCopy.tag = "EditorOnly";  // Change from initial value "Untagged"

Debug.Log(prefab.tag);     // "Untagged"   - expected
Debug.Log(prefabCopy.tag); // "EditorOnly" - expected

// Replace contents of prefab file with `prefabCopy`
PrefabUtility.ReplacePrefab(prefabCopy, prefab);

// Destroy the copy
DestroyImmediate(prefabCopy);

Debug.Log(prefab.tag);     // "EditorOnly"   - whoa?

別のオブジェクトをどのようprefabに指しているのでしょうか。

注:Unityは.NETのMonoフレーバーの上に構築されていることに注意してください

4

4 に答える 4

8

オブジェクトへのアクセスに使用される別のオブジェクトにオブジェクトを埋め込むと、これを行うことができます。

class ObjectReference<T>
   where T : new()
{
    private T _obj = new T();

    public void CreateNewObject()
    {
        _obj = new T();
    }

    public T Value { get return _obj; }
}

これで、タイプのオブジェクトへの複数の参照を作成しObjectReference、ローカルオブジェクトのみを変更できます。「実際の」オブジェクトには、Valueプロパティを介してアクセスします

少し異なるアプローチは、「実際の」オブジェクトと同じインターフェイスを実装するラッパーを作成して、このラッピングを透過的にすることです。

interface ISomeInterface
{
    string PropertyA { get; set }
    void MethodB (int x);
}

class TheRealObject : ISomeInterface
{
    public string PropertyA { get; set }

    public void MethodB (int x)
    {
        Console.WriteLine(x);
    }
}

class Wrapper : ISomeInterface
{
    TheRealObject _obj = new TheRealObject();

    public string PropertyA
    { 
        get { return _obj.PropertyA; }
        set { _obj.PropertyA = value; }
    }

    public void MethodB (int x)
    {
        _obj.MethodB(x);
    }

    public void CreateNewObject()
    {
        _obj = new TheRealObject();
    }
}

これで、ラッパーを「実際の」オブジェクトであるかのように使用できます。ラッパーのコンストラクターで「実際の」オブジェクトの初期インスタンスを渡し、のイニシャライザーを削除することもできます_obj

于 2012-07-07T18:32:16.700 に答える
6

オブジェクトの状態はフィールド値によって定義されるため、フィールド値を含むメモリを1つのオブジェクトから別のオブジェクトにコピーして、効果的に「置き換える」ことができます。

public static void Replace<T>(T x, T y)
    where T : class
{
    // replaces 'x' with 'y'
    if(x == null) throw new ArgumentNullException("x");
    if(y == null) throw new ArgumentNullException("y");

    var size = Marshal.SizeOf(typeof(T));
    var ptr = Marshal.AllocHGlobal(size);
    Marshal.StructureToPtr(y, ptr, false);
    Marshal.PtrToStructure(ptr, x);
    Marshal.FreeHGlobal(ptr);
}

このコードには、クラスに定義された[StructLayout(LayoutKind.Sequential)](または)属性が必要であることに注意してください。LayoutKind.Explicit

于 2012-07-07T18:14:38.130 に答える
4

いいえ、それは不可能です。

オブジェクトへのすべての参照を実際に変更するには、プロセス内のすべてのスレッドをフリーズし、それらのレジスタセットとスタックにアクセスする必要があります。これはガベージコレクターが行うことですが、通常のコードでは不可能です。

この方法で最も可能性が高いのは、一方のオブジェクトをもう一方のオブジェクトにディープコピーすることです。

于 2012-07-07T18:02:02.653 に答える
1

参照したいカスタムクラスの場合は、すべての参照が偽の参照を指すようにすることができると思います...

  1. クラスを作成する(A)
  2. クラスインターフェイス(IA)を作成します
  3. 含まれているオブジェクト(AC)へのすべての呼び出しを渡すだけのインターフェイスに基づいてラッパークラスを作成します

代入演算子を追加したので、すべてのAオブジェクトをACとして使用できます。

class AC:IA  
{  
    IA ref;  
    AC(IA ref)  
    {  
        this.ref = ref;  
    }  

    public void ChangeReference(IA newRef) { ref = newRef;}  
    public static operator = (IA assignedObj)  
    {  
        return (assignedObject is AC) ? assignedObject : new AC(assignedObj);
    }

    // implementation of all methods in A
    public override string ToString() { return ref.ToString(); }  
        ...  
}

これで、必要に応じて、ChangeReferenceメソッドを使用して、すべてを新しい参照に切り替えることができます。

C ++では、ReferencetoReferenceを使用します

幸運を祈ります

于 2012-07-07T18:31:18.643 に答える