c# - 使用 DLR 运行通过 CompileAssemblyFromSource 生成的代码?

标签 c# .net codedom dynamic-language-runtime

跟进 excellent answer ,我想知道使用 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[] { });
}

变成这样:

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

最佳答案

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

public interface IFoo
{
    string Execute();
}

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

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

这取决于您对动态代码的控制程度,这可能会也可能不会,但如果是的话,编译时进行类型检查是件好事。例如,如果您尝试执行:

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

第二行会因为拼写错误而立即编译失败,而使用 dynamic 关键字或反射时,该行会成功编译,但会导致运行时异常。例如,以下不会出现编译时错误:

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

关于c# - 使用 DLR 运行通过 CompileAssemblyFromSource 生成的代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10914484/

相关文章:

c# - 如何将 user.config 保存到 AppData\Roaming 文件夹而不是 AppData\Local?

c# - 是否可以让 Entity Framework 识别已创建但尚未保存在数据库中的对象?

c# - 卸载 CodeDom 编译的程序集

c# - .Net CodeDom - 在 .net 中实现 lambda 表达式

c# - 在测试期间覆盖 DateTime.Now 的好方法是什么?

c# - 签署 exe 会使通信变慢吗?

c# - 如何将不同类中的静态属性绑定(bind)到 WPF ListView 的 GridViewColumn?

.net - TargetFramework属性定义

.net - NHibernate:如何解决这个 "dialect"配置问题

c# - 如何通过Codedom实现 "Handles"