使用[Serializable]属性或MarshalByRefObject的子类化?

时间:2009-03-01 12:14:30

标签: c# remoting appdomain

我想在AppDomains中使用一个对象。

为此我可以使用[Serializableable]属性:

[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 个答案:

答案 0 :(得分:21)

使用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名称。

答案 1 :(得分:10)

这些方法产生了截然不同的效果。

使用MarshalByRef版本,您将创建一个对象实例。它将存在于新创建的AppDomain中。对象的所有访问都是通过TransparentProxy完成的。

使用Serializable版本,您可以创建2个对象实例。一个是在新创建的AppDomain中创建的。然后,CreateInstanceAndUnwrap调用将序列化此对象并在原始应用程序域中对其进行反序列化。这将创建与第一个版本完全独立的对象的第二个版本。事实上,下一个GC几乎肯定会消除原始对象,你将留下一个实例。

答案 2 :(得分:6)

  

为什么两种方法都有相同的效果?

他们具有相同的效果。

使用MarshalByRefObject,您将跨AppDomain边界引用一个对象。使用[Serializable]正在创建对象的副本。这将显示是否在子域中修改了对象的状态,然后再次检查(或执行子AppDomain中的Console.WriteLine)。

答案 3 :(得分:2)

MarshalByRefValueSerializable为远程处理/跨AppDomain通信实现了不同的语义。 MarshalByRefValue本质上通过代理对象为您提供引用语义,而Serializable为您提供值语义(即复制对象的状态)。

换句话说,MarshalByRefValue将允许您跨不同的AppDomain修改实例,而Serializable则不会。当您只需要从一个AppDomain获取信息到另一个AppDomain时,后者非常有用,例如:从一个AppDomain获取异常内容到另一个AppDomain。