Подтвердить что ты не робот

Использовать атрибут [Serializable] или подклассы из MarshalByRefObject?

Я хотел бы использовать объект через 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());

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

РЕДАКТИРОВАТЬ: На поверхности я знаю, что между обоими механизмами существуют различия, но если кто-то выскочил из куста и задал мне вопрос, я не мог дать ему правильный ответ. Вопросы - довольно открытые вопросы. Я надеялся, что кто-то сможет объяснить это лучше, чем я мог.

4b9b3361

Ответ 1

Использование 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 по умолчанию при вызове из объекта Serializable.

Ответ 2

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

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

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

Ответ 3

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

Они не имеют такого же эффекта.

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

Ответ 4

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

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