2009-03-01 6 views
16

Я хотел бы использовать объект через AppDomains.Используйте атрибут [Serializable] или подклассы из MarshalByRefObject?

Для этого можно использовать [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()); 

Почему оба подхода имеют одинаковый эффект? В чем разница в обоих подходах? Когда я должен одобрять один подход к другому?

EDIT: На поверхности я знаю, что между обоими механизмами существуют различия, но если кто-то выскочил из куста и задал мне вопрос, я не мог дать ему правильный ответ. Вопросы - довольно открытые вопросы. Я надеялся, что кто-то сможет объяснить это лучше, чем я мог.

ответ

20

Использование MarshallByRef будет выполнять ваши методы в удаленном AppDomain. Когда вы используете CreateInstanceAndUnwrap с объектом Serializable, копия объекта создается локальным 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()); 

    } 
} 

Этот код будет отображать «OtherAppDomain» при вызове WhatIsMyAppDomain от объекта MarshallByRef, и ваше имя AppDomain по умолчанию при вызове из сериализуемого объекта.

5

Почему оба подхода имеют одинаковый эффект?

Они не оказывают такое же влияние.

С MarshalByRefObject вы ссылаетесь на один объект через границы AppDomain. С [Serializable] копия объекта выполняется. Это будет отображаться, если состояние объекта будет изменено в дочернем домене, а затем снова рассмотрено (или выполнить Console.WriteLine внутри дочернего домена AppDomain).

+0

Хорошо ... изменили вопрос. Кажется *, поскольку оба подхода имеют такой же эффект. –

2

MarshalByRefValue и Serializable реализовать различную семантику для удаленного доступа/перекрестного общения через приложение. MarshalByRefValue по существу дает вам ссылочную семантику через прокси-объект, а Serializable дает вам семантику значений (т. Е. Состояние объекта копируется).

Иными словами, MarshalByRefValue позволит вам модифицировать экземпляр на разных объектах AppDomains, а Serializable - нет. Последнее полезно, когда вам просто нужно получить информацию от одного AppDomain к другому, например. для получения содержимого исключения из одного AppDomain в другое.

+1

Пожалуйста, оставьте комментарий при голосовании. Благодарю. –

9

Эти подходы имеют резко отличающиеся эффекты.

С помощью версии MarshalByRef вы создаете 1 экземпляр вашего объекта. Он будет жить во вновь созданном AppDomain. Весь доступ к объекту осуществляется через TransparentProxy.

С версией Serializable вы создали 2 экземпляра своего объекта. Один создается во вновь созданном AppDomain. Затем вызов CreateInstanceAndUnwrap сериализует этот объект и десериализует его в исходном домене приложения. Это создает вторую версию объекта, полностью независимую от первой. Фактически, самый следующий GC почти наверняка устранит исходный объект, и вам останется один экземпляр.

+0

+1 для ссылки на увлекательную запись в блоге о TransparentProxy. Эта статья действительно демистифицирует MarshalByRefObject (MBRO) для меня. Теперь мне просто интересно, что такое контекст и ContextBoundObject: :) – Qwertie

Смежные вопросы