简体   繁体   English

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

[英]Use the [Serializable] attribute or subclassing from MarshalByRefObject?

I'd like to use an object across AppDomains. 我想在AppDomains中使用一个对象。

For this I can use the [Serializeable] attribute: 为此,我可以使用[Serializeable]属性:

[Serializable]
class MyClass
{
    public string GetSomeString() { return "someString" }
}

Or subclass from MarshalByRefObject: 或MarshalByRefObject的子类:

class MyClass: MarshalByRefObject
{
    public string GetSomeString() { return "someString" }
}

In both cases I can use the class like this: 在这两种情况下,我都可以使用这样的类:

AppDomain appDomain = AppDomain.CreateDomain("AppDomain");
MyClass myObject = (MyClass)appDomain.CreateInstanceAndUnwrap(
                   typeof(MyClass).Assembly.FullName,
                   typeof(MyClass).FullName);
Console.WriteLine(myObject.GetSomeString());

Why do both approaches seem to have the same effect? 为什么两种方法似乎都有相同的效果? What is the difference in both approaches? 两种方法有什么不同? When should I favor the one approach over the other? 我什么时候应该支持另一种方法呢?

EDIT: At the surface I know that there are differences between both mechanisms, but if someone jumped out of a bush and asked me the question I couldn't give him a proper answer. 编辑:从表面上看,我知道两种机制之间存在差异,但如果有人跳出丛林并问我这个问题,我无法给他一个正确的答案。 The questions are quite open questions. 问题是非常开放的问题。 I hoped that someone can explain it better than I could do. 我希望有人可以比我能做的更好地解释它。

Using MarshallByRef will execute your methods in the remote AppDomain. 使用MarshallByRef将在远程AppDomain中执行您的方法。 When you use CreateInstanceAndUnwrap with a Serializable object, a copy of the object is made to the local AppDomain, so any method call will be executed in the local AppDomain. 当您将CreateInstanceAndUnwrap与Serializable对象一起使用时,该对象的副本将发送到本地AppDomain,因此任何方法调用都将在本地AppDomain中执行。

If what you want is to communicate between AppDomains go with the MarshallByRef approach. 如果您想要的是在AppDomains之间进行通信,请使用MarshallByRef方法。

An example: 一个例子:

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());

    }
}

This code will display "OtherAppDomain" when you call WhatIsMyAppDomain from the MarshallByRef object, and your default AppDomain name when you call from the Serializable object. 当您从MarshallByRef对象调用WhatIsMyAppDomain时,此代码将显示“OtherAppDomain”,当您从Serializable对象调用时,此代码将显示默认的AppDomain名称。

These approaches have dramatically different effects. 这些方法具有截然不同的效果。

With the MarshalByRef version you are creating 1 instance of your object. 使用MarshalByRef版本,您将创建一个对象实例。 It will live in the newly created AppDomain. 它将存在于新创建的AppDomain中。 All accesse to the object is done via a TransparentProxy . 对象的所有访问都是通过TransparentProxy完成的。

With the Serializable version you are created 2 instances of your object. 使用Serializable版本,您将创建2个对象实例。 One is created in the newly created AppDomain. 一个是在新创建的AppDomain中创建的。 The CreateInstanceAndUnwrap call will then serialize this object and deserialize it in the original app domain. 然后,CreateInstanceAndUnwrap调用将序列化此对象并在原始应用程序域中对其进行反序列化。 This creates a second version of the object that is completely independent from the first. 这将创建与第一个版本完全独立的对象的第二个版本。 In fact, the very next GC will almost certainly eliminate the original object and you'll be left with one instance. 事实上,下一个GC几乎肯定会消除原始对象,你将留下一个实例。

Why do both approaches have the same effect? 为什么两种方法都有相同的效果?

They do not have the same effect. 它们没有相同的效果。

With MarshalByRefObject you are referencing one object across AppDomain boundaries. 使用MarshalByRefObject您将跨AppDomain边界引用一个对象。 With [Serializable] a copy of the object is being made. 使用[Serializable]正在创建对象的副本。 This will show up if the state of the object is modified in the child domain and then examined again (or execute the Console.WriteLine inside the child AppDomain). 这将显示是否在子域中修改了对象的状态,然后再次检查(或在子AppDomain中执行Console.WriteLine )。

MarshalByRefValue and Serializable implement different semantics for remoting/cross AppDomain communication. MarshalByRefValueSerializable为远程处理/跨AppDomain通信实现了不同的语义。 MarshalByRefValue essentially gives you reference semantics through a proxy object, while Serializable gives you value semantics (ie the state of the object is copied). MarshalByRefValue本质上通过代理对象为您提供引用语义,而Serializable为您提供值语义(即复制对象的状态)。

In other words MarshalByRefValue will let you modify the instance across different AppDomains, while Serializable will not. 换句话说, MarshalByRefValue将允许您跨不同的AppDomain修改实例,而Serializable则不允许。 The latter is useful when you just need to get the information from one AppDomain to another, eg to get the content of an exception from one AppDomain to another. 当您只需要从一个AppDomain获取信息到另一个AppDomain时,后者非常有用,例如,将异常内容从一个AppDomain获取到另一个AppDomain。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM