Использовать атрибут [Serializable] или подклассы из MarshalByRefObject? - PullRequest
17 голосов
/ 01 марта 2009

Я хотел бы использовать объект в доменах приложений.

Для этого я могу использовать атрибут [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 ]

21 голосов
/ 01 марта 2009

Использование MarshallByRef выполнит ваши методы в удаленном домене приложений. Когда вы используете CreateInstanceAndUnwrap с объектом Serializable, копия этого объекта создается в локальном домене приложений, поэтому любой вызов метода будет выполняться в локальном домене приложений.

Если вы хотите общаться между доменами приложений, используйте подход 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 по умолчанию при вызове из объекта Serializable.

10 голосов
/ 01 марта 2009

Эти подходы имеют совершенно разные эффекты.

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

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

6 голосов
/ 01 марта 2009

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

Они не имеют одинаковый эффект.

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

2 голосов
/ 01 марта 2009

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

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

...