混合MarshalByRefObject和Serializable

Qwe*_*tie 6 .net remoting serialization appdomain marshalbyrefobject

各种消息来源解释说

当对象从MarshalByRefObject派生时,对象引用将从一个应用程序域传递到另一个应用程序域而不是对象本身.当一个对象用[Serializable]标记时,该对象将自动序列化,从一个应用程序域传输到另一个应用程序域,然后反序列化以在第二个应用程序域中生成该对象的精确副本.请注意,当MarshalByRefObject传递引用时,[Serializable]会导致复制对象.[资源]

我正在设计我的第一个使用AppDomains的应用程序,我想知道当您对MarshalByRefObjects可执行MarshalByRefObject的可序列化对象内部的引用时会发生什么,因为到目前为止我找不到关于该主题的任何文档.

例如,如果我尝试返回跨AppDomain边界的List<MBR>位置会发生什么MBR : MarshalByRefObject?我是否获得原始对象的List<MBR>每个MBR位置 的副本TransparentProxy?有没有关于混合这两种机制的技术细节的文档?

Qwe*_*tie 7

我只是做了一个快速测试,List<MBR>它似乎按照我的希望工作:

public class MBR : MarshalByRefObject
{
    List<MBR> _list;
    public MBR() { _list = new List<MBR> { this }; }
    public IList<MBR> Test() { return _list; }
    public int X { get; set; }
}

// Later...
var mbr = AppDomainStarter.Start<MBR>(@"C:\Program Files", "test", null, true);
var list = mbr.Test();
list[0].X = 42;
list.Clear();
Debug.WriteLine(string.Format("X={0}, Count={1}", mbr.X, mbr.Test().Count));
Run Code Online (Sandbox Code Playgroud)

输出是X=42, Count=1,调试器显示List<MBR>包含a __TransparentProxy.很明显,MarshalByRefObject通过引用成功封送了另一个被值封送的对象.

如果有人能找到一些,我仍然希望看到文档或技术细节.

对于任何好奇的人,我都写了这个方便的沙盒AppDomainStarter:

/// <summary><see cref="AppDomainStarter.Start"/> starts an AppDomain.</summary>
public static class AppDomainStarter
{
    /// <summary>Creates a type in a new sandbox-friendly AppDomain.</summary>
    /// <typeparam name="T">A trusted type derived MarshalByRefObject to create 
    /// in the new AppDomain. The constructor of this type must catch any 
    /// untrusted exceptions so that no untrusted exception can escape the new 
    /// AppDomain.</typeparam>
    /// <param name="baseFolder">Value to use for AppDomainSetup.ApplicationBase.
    /// The AppDomain will be able to use any assemblies in this folder.</param>
    /// <param name="appDomainName">A friendly name for the AppDomain. MSDN
    /// does not state whether or not the name must be unique.</param>
    /// <param name="constructorArgs">Arguments to send to the constructor of T,
    /// or null to call the default constructor. Do not send arguments of 
    /// untrusted types this way.</param>
    /// <param name="partialTrust">Whether the new AppDomain should run in 
    /// partial-trust mode.</param>
    /// <returns>A remote proxy to an instance of type T. You can call methods 
    /// of T and the calls will be marshalled across the AppDomain boundary.</returns>
    public static T Start<T>(string baseFolder, string appDomainName, 
        object[] constructorArgs, bool partialTrust)
        where T : MarshalByRefObject
    {
        // With help from http://msdn.microsoft.com/en-us/magazine/cc163701.aspx
        AppDomainSetup setup = new AppDomainSetup();
        setup.ApplicationBase = baseFolder;

        AppDomain newDomain;
        if (partialTrust) {
            var permSet = new PermissionSet(PermissionState.None);
            permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
            permSet.AddPermission(new UIPermission(PermissionState.Unrestricted));
            newDomain = AppDomain.CreateDomain(appDomainName, null, setup, permSet);
        } else {
            newDomain = AppDomain.CreateDomain(appDomainName, null, setup);
        }
        return (T)Activator.CreateInstanceFrom(newDomain, 
            typeof(T).Assembly.ManifestModule.FullyQualifiedName, 
            typeof(T).FullName, false,
            0, null, constructorArgs, null, null).Unwrap();
    }
}
Run Code Online (Sandbox Code Playgroud)