使用DLR运行用CompileAssemblyFromSource生成的代码?

5 .net c# codedom dynamic-language-runtime

继续这个优秀的答案,我想知道使用dynamic关键字的DLR是否允许更简洁的方式为生成的程序集编写代码.

例如,上述答案的代码可以:

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[] { });
}
Run Code Online (Sandbox Code Playgroud)

变成这样的东西:

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();
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*art 7

是的,你可以做到这一点并且效果很好.但是,虽然使用动态关键字更方便,但它使用后期绑定,并且在这个意义上仍然是不安全的,因为显式使用反射.如果您的设计允许,最好使用共享接口或基类进行早期绑定.您可以通过在程序集或第三个共享程序集中创建公共类型,然后从正在动态编译的新程序集中添加对该程序集的引用来完成此操作.然后,在生成的代码中,您可以从引用的程序集中的该共享类型继承.例如,创建一个接口:

public interface IFoo
{
    string Execute();
}
Run Code Online (Sandbox Code Playgroud)

然后像这样动态编译程序集:

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();
}
Run Code Online (Sandbox Code Playgroud)

根据您对动态代码的控制程度,这可能会也可能不会成为可能,但是当它成功时,进行编译时类型检查会很好.例如,如果您尝试执行:

IFoo obj = (IFoo)Activator.CreateInstance(type);
obj.Execcute();
Run Code Online (Sandbox Code Playgroud)

第二行将立即无法编译,因为它拼写错误,而使用动态关键字或反射,该行将成功编译,但它会导致运行时异常.例如,以下内容不会出现编译时错误:

dynamic obj = Activator.CreateDynamicInstance(type);
obj.Execcute();
Run Code Online (Sandbox Code Playgroud)