2012-06-06 10 views
5

Siguiendo en este excellent answer, me pregunto si el DLR que usa la palabra clave dynamic puede permitir una forma menos detallada de escribir código para el ensamblado generado.Use DLR para ejecutar el código generado con CompileAssemblyFromSource?

Por ejemplo, puede código de la respuesta mencionada:

using (Microsoft.CSharp.CSharpCodeProvider foo = 
      new Microsoft.CSharp.CSharpCodeProvider()) 
{ 
    var res = foo.CompileAssemblyFromSource(
     new System.CodeDom.Compiler.CompilerParameters() { 
      GenerateInMemory = true 
     }, 
     "public class FooClass { public string Execute() { return \"output!\";}}" 
    ); 

    var type = res.CompiledAssembly.GetType("FooClass"); 
    var obj = Activator.CreateInstance(type); 
    var output = type.GetMethod("Execute").Invoke(obj, new object[] { }); 
} 

convertido en algo así como:

using (Microsoft.CSharp.CSharpCodeProvider foo = 
      new Microsoft.CSharp.CSharpCodeProvider()) 
{ 
    var res = foo.CompileAssemblyFromSource(
     new System.CodeDom.Compiler.CompilerParameters() { 
      GenerateInMemory = true 
     }, 
     "public class FooClass { public string Execute() { return \"output!\";}}" 
    ); 

    var type = res.CompiledAssembly.GetType("FooClass"); 
    dynamic obj = Activator.CreateDynamicInstance(type); 
    var output = obj.Execute(); 
} 
+1

Sí, hay un código un poco menos. Hazlo funcionar usando en su lugar 'Activator.CreateInstance()'. No veo una pregunta de lo contrario. –

+1

Sí, lo probé y me di cuenta de que "simplemente funciona" con 'dynamic' en lugar de' var'. Bastante genial. –

Respuesta

7

Sí, puede hacerlo y funciona bien. Sin embargo, si bien utilizar la palabra clave dinámica es más conveniente, utiliza la vinculación tardía y sigue siendo tan inseguro, en ese sentido, como el uso explícito de la reflexión. Si su diseño lo permite, es incluso mejor utilizar una interfaz compartida o una clase base para el enlace anticipado. Puede hacer esto creando un tipo público en su ensamblado o en un tercer ensamblaje compartido, y luego agregue una referencia a ese ensamblaje desde el nuevo que está compilando dinámicamente. Luego, en el código generado, puede heredar de ese tipo compartido en el ensamblado al que se hace referencia. Por ejemplo, crear una interfaz:

public interface IFoo 
{ 
    string Execute(); 
} 

a continuación, compilar dinámicamente el conjunto de la siguiente manera:

using (Microsoft.CSharp.CSharpCodeProvider foo = new Microsoft.CSharp.CSharpCodeProvider()) 
{ 
    var params = new System.CodeDom.Compiler.CompilerParameters(); 
    params.GenerateInMemory = true; 

    // Add the reference to the current assembly which defines IFoo 
    params.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location); 

    // Implement the IFoo interface in the dynamic code 
    var res = foo.CompileAssemblyFromSource(params, "public class FooClass : IFoo { public string Execute() { return \"output!\";}}"); 
    var type = res.CompiledAssembly.GetType("FooClass"); 

    // Cast the created object to IFoo 
    IFoo obj = (IFoo)Activator.CreateInstance(type); 

    // Use the object through the IFoo interface 
    obj.Execute(); 
} 

Dependiendo de la cantidad de control que tiene sobre el código dinámico, esto puede o no puede ser posible, pero cuando lo es, es bueno tener la comprobación de tipos en tiempo de compilación. Por ejemplo, si se trató de ejecutar:

IFoo obj = (IFoo)Activator.CreateInstance(type); 
obj.Execcute(); 

Esa segunda línea sería un fracaso inmediato la compilación porque está mal escrito, mientras que con la palabra clave o la reflexión dinámica, esa línea sería compilar correctamente pero podría causar un tiempo de ejecución excepción. Por ejemplo, el siguiente no obtendrá un error en tiempo de compilación:

dynamic obj = Activator.CreateDynamicInstance(type); 
obj.Execcute(); 
+0

gracias por la respuesta elaborada (+1), pero tengo que estar en desacuerdo con su afirmación "aunque es más conveniente hacerlo de esa manera, ninguna de las dos maneras es segura". Pueden producirse errores de enlace porque la seguridad de tipo está asegurada. Su afirmación sería correcta con el escenario opuesto donde no ocurriría ningún error vinculante cuando debería. –

+0

No estoy seguro exactamente a qué te refieres, pero modifiqué mi respuesta para que quede más claro. –

+0

Creo que fue muy claro al decir que era incorrecto al decir que el enfoque no es seguro. –

0

Ese es uno de los escenarios que el DLR fue diseñado. Puede usarlo de esa forma para invocar a los miembros de un tipo cargado dinámicamente mientras evita todas las operaciones de tipeo adicionales al llamar manualmente al .GetMethod() y al .Invoke().

+0

¿Cómo, exactamente? . . . –

+0

Exactamente como la pregunta se muestra en su ejemplo. Tenga en cuenta las diferencias entre las dos últimas líneas en cada uno. –

Cuestiones relacionadas