2012-01-07 20 views
6

Diversas fuentes explican quemezcla MarshalByRefObject y serializables

Cuando un objeto se deriva forma MarshalByRefObject, una referencia de objeto se pasa de un dominio de aplicación a otro lugar del objeto sí mismo. Cuando un objeto está marcado con [Serializable], el objeto se serializará automáticamente, se transportará desde un dominio de aplicación a otro y luego se deserializará para producir una copia exacta del objeto en el segundo dominio de aplicación. Observe luego que mientras MarshalByRefObject pasa una referencia, [Serializable] hace que el objeto se copie. [source]

estoy diseñando mi primera aplicación que utiliza dominios de aplicación y me pregunto qué sucede cuando haga referencias a MarshalByRefObjects dentro de los objetos serializables que no implementan MarshalByRefObject, ya que hasta ahora no puedo encontrar ninguna documentación sobre el tema.

Por ejemplo, ¿qué sucede si trato de devolver un List<MBR> donde MBR : MarshalByRefObject a través de un límite de AppDomain? ¿Obtengo una copia del List<MBR> donde cada MBR es un TransparentProxy para el objeto original? ¿Y hay alguna documentación sobre los detalles técnicos de la mezcla de los dos mecanismos?

Respuesta

7

que acabo de hacer una prueba rápida con List<MBR> y parece que funciona como esperaba:

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

La salida es X=42, Count=1 y el depurador muestra que el List<MBR> contiene una __TransparentProxy. Entonces, claramente, el MarshalByRefObject se calcula con éxito por referencia dentro de otro objeto que se calculó por valor.

Todavía me gustaría ver documentación o detalles técnicos si alguien puede encontrar alguno.

Para cualquier persona que tenga curiosidad, he escrito este práctico-excelente AppDomainStarter caja de arena:

/// <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(); 
    } 
} 
0

Tengo entendido que solo el objeto de nivel superior que se pasa puede ser MBR. En su escenario, dado que List no es MBR, cuando se pase por encima del límite, recibirá copias serializadas.

En esta sección se explica en el MSDN documentation este comportamiento:

MarshalByRefObject es la clase base para objetos que se comunican a través de los límites del dominio de aplicación mediante el intercambio de mensajes a través de un proxy. Los objetos que no heredan de MarshalByRefObject son implícitamente mariscales por valor. Cuando una aplicación remota hace referencia a un objeto Marshal por valor, se pasa una copia del objeto a través de los límites del dominio de la aplicación.

Por lo tanto, dado que la clase (Lista) que se pasa no es MBR, se serializará, junto con su contenido.

Asimismo, si bien no es directamente aplicable a la cuestión, el siguiente comportamiento es muy importante tener en cuenta:

... los miembros del objeto no se pueden utilizar fuera del dominio de aplicación en el que fueron creados.

+0

Así que si MBR no es Serializable, habrá una excepción de algún tipo cuando el .NET Framework intenta serializarlo ? ¿Qué hay de devolver matrices MBR []? System.Array es serializable y no derivado de MarshalByRefObject. – Qwertie

+0

re no es serializable: sí, se producirá una excepción en el tiempo de ejecución. re arrays MBR: tiene el mismo problema que List, ya que array es la clase de nivel superior. –

+2

El experimento muestra que un MBR no serializable dentro de un contenedor serializable se pasa por referencia sin excepción. –