2012-06-06 11 views
5

Seguendo questo excellent answer, mi chiedo se il DLR che utilizza la parola chiave dynamic possa consentire un modo meno dettagliato di scrivere il codice per l'assembly generato.Utilizzare DLR per eseguire il codice generato con CompileAssemblyFromSource?

per esempio, può codice del citato risposta:

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[] { }); 
} 

diventare qualcosa di simile:

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ì, c'è un po 'meno codice. Farlo funzionare usando "Activator.CreateInstance()" invece. Altrimenti non vedo una domanda. –

+1

Sì, l'ho appena provato e ho capito che "funziona" con 'dynamic' invece di' var'. Roba molto interessante –

risposta

7

Sì, lo puoi fare e funziona bene. Tuttavia, mentre l'uso della parola chiave dinamica è più conveniente, utilizza l'associazione tardiva ed è ancora altrettanto pericoloso, in questo senso, poiché utilizza in modo esplicito la riflessione. Se il tuo design lo consente, è ancora meglio utilizzare un'interfaccia condivisa o una classe base per l'associazione anticipata. È possibile farlo creando un tipo pubblico nell'assieme o in un terzo assembly condiviso, quindi aggiungere un riferimento a quell'assieme dal nuovo che si sta compilando in modo dinamico. Quindi, nel codice generato, puoi ereditare da quel tipo condiviso nell'assembly referenziato. Ad esempio, creare un'interfaccia:

public interface IFoo 
{ 
    string Execute(); 
} 

quindi compilare in modo dinamico l'assemblea in questo modo:

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

A seconda di quanto il controllo si hanno a disposizione il codice dinamico, questo può o non può essere possibile, ma quando lo è, è bello avere il controllo del tipo in fase di compilazione. Per esempio, se si è tentato di eseguire:

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

Quella seconda linea avrebbe immediatamente non riuscire a compilare perché è scritta male, mentre con la parola chiave dinamico o riflessione, che la linea sarebbe compilare correttamente ma causerebbe un run-time eccezione. Ad esempio, il seguente errore non verrà visualizzato in fase di compilazione:

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

grazie per l'elaborata risposta (+1), ma non sono d'accordo con la tua affermazione "mentre è più conveniente farlo in questo modo, nessuno dei due è sicuro dal punto di vista del tipo". Gli errori di binding possono verificarsi perché il tipo di sicurezza è assicurato. La tua affermazione sarebbe corretta con lo scenario opposto in cui non si verificherebbe alcun errore di associazione. –

+0

Non sono sicuro di cosa intendi, ma ho modificato la mia risposta per renderla più chiara. –

+0

Credo di essere stato abbastanza chiaro dicendo che non eri corretto nel dire che l'approccio non è sicuro. –

0

Questo è uno degli scenari che la DLR è stato progettato per. È possibile utilizzarlo in questo modo per invocare membri di un tipo caricato dinamicamente evitando tutti i tipi di digitazione aggiuntivi da chiamare manualmente .GetMethod() e .Invoke().

+0

Come, esattamente? . . . –

+0

Esattamente come la domanda mostra nel suo esempio. Nota le differenze tra le ultime due righe in ciascuna. –

Problemi correlati