使用属性或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());
为什么两种方法似乎都有相同的效果? 两种方法有什么不同? 什么时候我应该赞成一种方法而不是另一种呢?
编辑:从表面上看,我知道两种机制之间存在差异,但如果有人跳出丛林并问我这个问题,我无法给他一个正确的答案。 问题是非常开放的问题。 我希望有人可以比我能做的更好地解释它。
使用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()); } }
当您从MarshallByRef对象调用WhatIsMyAppDomain时,此代码将显示“OtherAppDomain”,当您从Serializable对象调用时,此代码将显示您的默认AppDomain名称。
这些方法具有截然不同的效果。
使用MarshalByRef版本,您将创建对象的1个实例。 它将存在于新创建的AppDomain中。 对象的所有访问都是通过TransparentProxy完成的。
使用Serializable版本,您可以创建2个对象实例。 一个是在新创建的AppDomain中创建的。 然后,CreateInstanceAndUnwrap调用将序列化此对象并在原始应用程序域中对其进行反序列化。 这将创建完全独立于第一个版本的对象的第二个版本。 事实上,下一个GC几乎肯定会消除原始对象,你将留下一个实例。
为什么两种方法都有相同的效果?
它们没有相同的效果。
使用MarshalByRefObject
您将跨AppDomain边界引用一个对象。 使用[Serializable]
,正在创建对象的副本。 这将显示是否在子域中修改了对象的状态,然后再次检查(或在子AppDomain中执行Console.WriteLine
)。
MarshalByRefValue
和Serializable
为远程处理/跨AppDomain通信实现了不同的语义。 MarshalByRefValue
本质上通过代理对象为您提供引用语义,而Serializable
为您提供值语义(即复制对象的状态)。
换句话说, MarshalByRefValue
将允许您跨不同的AppDomain修改实例,而Serializable
则不允许。 当您只需要将信息从一个AppDomain获取到另一个AppDomain时,后者非常有用,例如,将exception内容从一个AppDomain获取到另一个AppDomain。