2009-03-01 15 views
16

Chciałbym użyć obiektu w AppDomains.Użyj atrybutu [Serializable] lub podklasy z MarshalByRefObject?

W tym celu można użyć [Serializeable] atrybut:

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

lub podklasy z MarshalByRefObject:

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

W obu przypadkach można użyć klasy tak:

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

Dlaczego oba podejścia wydają się mieć taki sam efekt? Jaka jest różnica w obu podejściach? Kiedy powinienem faworyzować jedno podejście do drugiego?

EDYCJA: Na powierzchni wiem, że istnieją różnice między oboma mechanizmami, ale jeśli ktoś wyskoczył z krzaka i zadał mi pytanie, nie mogłem mu dać właściwej odpowiedzi. Pytania są dość otwarte. Miałem nadzieję, że ktoś może wyjaśnić to lepiej niż ja.

Odpowiedz

20

Używanie MarshallByRef spowoduje wykonanie twoich metod w zdalnej domenie AppDomain. Gdy używasz CreateInstanceAndUnwrap z obiektem Serializable, kopia obiektu jest wprowadzana do lokalnej domeny AppDomain, więc każde wywołanie metody zostanie wykonane w lokalnej domenie AppDomain.

Jeśli chcesz komunikować się między AppDomains, zastosuj podejście MarshallByRef.

Przykład:

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()); 

    } 
} 

Ten kod wyświetli „OtherAppDomain” podczas rozmowy WhatIsMyAppDomain od obiektu MarshallByRef i domyślną nazwę AppDomain podczas rozmowy z Serializable obiektu.

5

Dlaczego oba podejścia mają taki sam efekt?

Zrobić nie mają taki sam efekt.

W przypadku MarshalByRefObject odwołujesz się do jednego obiektu w obrębie granic AppDomain. W przypadku [Serializable] tworzona jest kopia obiektu. Spowoduje to wyświetlenie stanu obiektu w domenie podrzędnej, a następnie jego ponowne sprawdzenie (lub wykonanie Console.WriteLine w potomnej domenie AppDomain).

+0

Dobrze ... zmieniłem pytanie. To * wydaje się *, ponieważ oba podejścia mają taki sam efekt. –

2

MarshalByRefValue i Serializable implementują inną semantykę do zdalnego/krzyżowego komunikowania się z AppDomain. MarshalByRefValue zasadniczo udostępnia semantykę odniesienia za pośrednictwem obiektu proxy, natomiast Serializable podaje semantykę wartości (tj. Stan obiektu jest kopiowany).

Innymi słowy, MarshalByRefValue pozwoli ci zmodyfikować instancję w różnych AppDomains, podczas gdy Serializable nie. Ta ostatnia jest przydatna, gdy potrzebujesz tylko uzyskać informacje z jednej domeny AppDomena na inną, np. aby uzyskać treść wyjątku od jednego elementu AppDomain do innego.

+1

Proszę zostaw komentarz podczas głosowania w dół. Dzięki. –

9

Podejścia te mają diametralnie różne efekty.

Przy wersji MarshalByRef tworzysz 1 wystąpienie obiektu. Będzie żyć w nowo utworzonej aplikacji AppDomain. Cały dostęp do obiektu odbywa się przez TransparentProxy.

W wersji Serializable powstają 2 wystąpienia obiektu. Jeden jest tworzony w nowo utworzonym AppDomain. Wywołanie CreateInstanceAndUnwrap spowoduje serializację tego obiektu i deserializację go w oryginalnej domenie aplikacji. Tworzy to drugą wersję obiektu, który jest całkowicie niezależny od pierwszego. W rzeczywistości, następny GC prawie na pewno wyeliminuje oryginalny obiekt, a zostanie ci tylko jedno wystąpienie.

+0

+1 za link do fascynującego wpisu na blogu o TransparentProxy. Ten artykuł naprawdę demistyfikuje dla mnie MarshalByRefObject (MBRO). Teraz właśnie zastanawiam się co do cholery Kontekst i ContextBoundObject jest :) – Qwertie

Powiązane problemy