Использовать атрибут [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());
Почему кажется, что оба подхода имеют одинаковый эффект? В чем разница в обоих подходах? Когда следует отдавать предпочтение одному подходу перед другим?
РЕДАКТИРОВАТЬ: На первый взгляд я знаю, что между обоими механизмами есть различия, но если кто-то выпрыгнет из куста и задаст мне вопрос, я не смогу дать ему правильного ответа. Вопросы довольно открытые. Я надеялся, что кто-нибудь сможет объяснить это лучше, чем я.
Ответов (4)4
Использование 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.
Почему оба подхода имеют одинаковый эффект?
Они не имеют такого же эффекта.
С MarshalByRefObject
вы ссылаетесь на один объект через границы домена приложений. С [Serializable]
копии объекта делается. Это будет отображаться, если состояние объекта будет изменено в дочернем домене, а затем снова проверено (или выполнено Console.WriteLine
внутри дочернего домена приложения ).
MarshalByRefValue
и Serializable
реализовать другую семантику для удаленного взаимодействия / связи между доменами приложений. MarshalByRefValue
по существу дает вам ссылочную семантику через прокси-объект, в то время как Serializable
дает вам семантику значений (т. е. состояние объекта копируется).
Другими словами MarshalByRefValue
, вы сможете изменять экземпляр в разных доменах приложений, а Serializable
не - нет. Последнее полезно, когда вам просто нужно получить информацию из одного домена приложения в другой, например, чтобы получить содержимое исключения из одного домена приложения в другой.
Эти подходы имеют совершенно разные эффекты.
С версией MarshalByRef вы создаете 1 экземпляр вашего объекта. Он будет жить во вновь созданном домене приложений. Весь доступ к объекту осуществляется через TransparentProxy .
В версии Serializable вы создаете 2 экземпляра вашего объекта. Один создается во вновь созданном домене приложений. Затем вызов CreateInstanceAndUnwrap сериализует этот объект и десериализует его в исходном домене приложения. Это создает вторую версию объекта, полностью независимую от первой. Фактически, следующий сборщик мусора почти наверняка удалит исходный объект, и у вас останется один экземпляр.