17

AppDomains 全体でオブジェクトを使用したいと考えています。

このために、[Serializeable] 属性を使用できます。

[Serializable]
class MyClass
{
    public string GetSomeString() { return "someString" }
}

または、MarshalByRefObject からサブクラス化します。

class MyClass: MarshalByRefObject
{
    public string GetSomeString() { return "someString" }
}

どちらの場合も、次のようにクラスを使用できます。

AppDomain appDomain = AppDomain.CreateDomain("AppDomain");
MyClass myObject = (MyClass)appDomain.CreateInstanceAndUnwrap(
                   typeof(MyClass).Assembly.FullName,
                   typeof(MyClass).FullName);
Console.WriteLine(myObject.GetSomeString());

両方のアプローチが同じ効果があるように見えるのはなぜですか? 両方のアプローチの違いは何ですか?あるアプローチを他のアプローチよりも優先する必要があるのはいつですか?

編集: 表面的には、両方のメカニズムに違いがあることはわかっていますが、誰かが茂みから飛び出して私に質問をした場合、私は彼に適切な答えを与えることができませんでした. 質問はかなりオープンな質問です。誰かが私よりもうまく説明できることを願っていました。

4

4 に答える 4

21

MarshallByRef を使用すると、リモート AppDomain でメソッドが実行されます。Serializable オブジェクトで CreateInstanceAndUnwrap を使用すると、オブジェクトのコピーがローカル AppDomain に作成されるため、すべてのメソッド呼び出しはローカル AppDomain で実行されます。

AppDomains 間の通信が必要な場合は、MarshallByRef アプローチを使用します。

例:

using System;
using System.Reflection;

[Serializable]
public class SerializableClass
{
    public string WhatIsMyAppDomain()
    {
        return AppDomain.CurrentDomain.FriendlyName;
    }
}

public class MarshallByRefClass : MarshalByRefObject
{
    public string WhatIsMyAppDomain()
    {
        return AppDomain.CurrentDomain.FriendlyName;
    }
}    

class Test
{

    static void Main(string[] args)
    {
        AppDomain ad = AppDomain.CreateDomain("OtherAppDomain");

        MarshallByRefClass marshall = (MarshallByRefClass)ad.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "MarshallByRefClass");
        SerializableClass serializable = (SerializableClass)ad.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "SerializableClass");

        Console.WriteLine(marshall.WhatIsMyAppDomain());
        Console.WriteLine(serializable.WhatIsMyAppDomain());

    }
}

このコードは、MarshallByRef オブジェクトから WhatIsMyAppDomain を呼び出すと「OtherAppDomain」を表示し、Serializable オブジェクトから呼び出すとデフォルトの AppDomain 名を表示します。

于 2009-03-01T12:54:18.530 に答える
10

これらのアプローチは劇的に異なる効果をもたらします。

MarshalByRefバージョンでは、オブジェクトのインスタンスを1つ作成しています。新しく作成されたAppDomainに存在します。オブジェクトへのすべてのアクセスは、TransparentProxyを介して行われます。

シリアル化可能なバージョンでは、オブジェクトの2つのインスタンスが作成されます。1つは、新しく作成されたAppDomainに作成されます。次に、CreateInstanceAndUnwrap呼び出しは、このオブジェクトをシリアル化し、元のアプリドメインで逆シリアル化します。これにより、最初のバージョンから完全に独立した2番目のバージョンのオブジェクトが作成されます。実際、次のGCはほぼ確実に元のオブジェクトを削除し、1つのインスタンスが残ります。

于 2009-03-01T18:26:19.603 に答える
6

両方のアプローチが同じ効果をもたらすのはなぜですか?

同じ効果はありません。

MarshalByRefObjectAppDomain の境界を越えて 1 つのオブジェクトを参照しています。[Serializable]オブジェクトのコピーが作成されています。これは、オブジェクトの状態が子ドメインで変更され、再度検査される (Console.WriteLineまたは子 AppDomain 内で実行される) 場合に表示されます。

于 2009-03-01T12:22:03.660 に答える
2

MarshalByRefValueSerializableリモート処理/クロス AppDomain 通信用のさまざまなセマンティクスを実装します。MarshalByRefValue基本的に、プロキシ オブジェクトを介して参照セマンティクスをSerializable提供しますが、値セマンティクスを提供します (つまり、オブジェクトの状態がコピーされます)。

つまりMarshalByRefValue、異なる AppDomain 間でインスタンスを変更できますが、そうでSerializableはありません。後者は、ある AppDomain から別の AppDomain に情報を取得する必要がある場合 (たとえば、ある AppDomain から別の AppDomain に例外の内容を取得する場合など) に役立ちます。

于 2009-03-01T14:32:28.607 に答える