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

继续这个优秀的答案后 ,我想知道使用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(); } 

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

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

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

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

这是DLR设计的场景之一。 您可以通过这种方式调用动态加载类型的成员,同时避免手动调用.GetMethod().Invoke()所有额外输入。