2012-06-06 10 views
5

Kontynuując ten excellent answer, zastanawiam się, czy DLR za pomocą słowa kluczowego dynamic może pozwolić na mniej szczegółowy sposób pisania kodu dla wygenerowanego zespołu.Użyj funkcji DLR do uruchomienia kodu wygenerowanego za pomocą CompileAssemblyFromSource?

Można na przykład kod wymienionej powyżej zwrotna:

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

stać się coś takiego:

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

Tak, jest trochę mniej kodu. Zrób to działa, używając zamiast tego 'Activator.CreateInstance()'. Nie widzę innego pytania. –

+1

Tak, po prostu wypróbowałem i zdałem sobie sprawę, że "po prostu działa" z 'dynamic' zamiast' var'. Całkiem fajne rzeczy. –

Odpowiedz

7

Tak, możesz to zrobić i działa dobrze. Jednak korzystanie z dynamicznego słowa kluczowego jest wygodniejsze, ponieważ wykorzystuje późniejsze wiązanie i nadal jest tak samo niebezpieczne, w tym sensie, jak jawnie za pomocą refleksji. Jeśli twój projekt na to pozwala, lepiej jest użyć wspólnego interfejsu lub klasy bazowej do wczesnego wiązania. Można to zrobić, tworząc typ publiczny w zespole lub w trzecim zespole współużytkowanym, a następnie dodać odwołanie do tego zestawu z nowego zestawu dynamicznie kompilowanego. Następnie w wygenerowanym kodzie można dziedziczyć z tego typu współużytkowanego w zespole referencyjnym. Na przykład utworzyć interfejs:

public interface IFoo 
{ 
    string Execute(); 
} 

Następnie dynamicznie skompilować zespół tak:

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

W zależności od tego, jak dużo kontroli masz nad kodem dynamicznym, to może być lub może nie być możliwe, ale kiedy to jest, miło jest mieć kontrolę typu kompilacji. Na przykład, jeśli próbował wykonać:

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

To druga linia natychmiast nie skompilować, ponieważ jest napisane źle, natomiast z dynamicznym słowa kluczowego lub refleksji, że linia będzie pomyślnie skompilować, ale spowodowałoby to run-time wyjątek. Na przykład poniższe błędy nie będą miały błędu kompilacji:

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

dziękuję za skomplikowaną odpowiedź (+1), ale muszę się nie zgodzić z twoim stwierdzeniem "podczas gdy wygodniej jest robić to w ten sposób, w żaden sposób nie jest bezpieczny dla typu". Mogą wystąpić błędy wiązania, ponieważ zapewnione jest bezpieczeństwo typu. Twoje zdanie byłoby poprawne w przeciwnym scenariuszu, w którym nie wystąpiłby żaden błąd wiążący. –

+0

Nie jestem pewien, co dokładnie masz na myśli, ale zmodyfikowałem swoją odpowiedź, aby było bardziej zrozumiałe. –

+0

Sądzę, że całkiem jasno powiedziałem, że nie miałeś racji twierdząc, że podejście to nie jest bezpieczne. –

0

To jeden ze scenariuszy, że DLR został zaprojektowany dla. Możesz go użyć w ten sposób, aby wywołać członków dynamicznie ładowanego typu, unikając jednocześnie dodatkowego pisania z ręcznego wywoływania .GetMethod() i .Invoke().

+0

Jak dokładnie? . . . –

+0

Dokładnie tak, jak pokazuje to pytanie w swoim przykładzie. Zwróć uwagę na różnice między ostatnimi dwoma liniami w każdym z nich. –

Powiązane problemy