Mixing MarshalByRefObject and Serializable

那年仲夏 提交于 2019-11-30 14:33:10

I just did a quick test with List<MBR> and it seems to work as I had hoped:

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

The output is X=42, Count=1, and the debugger shows that the List<MBR> contains a __TransparentProxy. So clearly, the MarshalByRefObject is successfully marshaled by reference inside another object that was marshaled by value.

I would still like to see documentation or technical details if anyone can find some.

For anyone who is curious, I wrote this handy-dandy sandbox 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();
    }
}

It is my understanding that only the top-level object that is passed may be MBR. In your scenario, since List is not MBR, when it is passed over the boundary, you will receive serialized copies.

This section in the MSDN documentation explains this behavior:

MarshalByRefObject is the base class for objects that communicate across application domain boundaries by exchanging messages using a proxy. Objects that do not inherit from MarshalByRefObject are implicitly marshal by value. When a remote application references a marshal by value object, a copy of the object is passed across application domain boundaries.

So, since the class (List) that is passed is not MBR, it will be serialized, along with its contents.

Also, while not directly applicable to the question, the following behavior is very important to note:

... the members of the object are not usable outside the application domain where they were created.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!