我正在尝试为我的应用程序添加一些特定的模块化功能,我需要用户能够创建自己的类,然后在运行时将它们导入到程序中,这些类将遵循特定的模板,因此我可以调用函数在他们的新课程中。
例如,一个类可以是:http://pastebin.com/90NTjia9
我会编译该类,然后执行doSomething();
我如何在C#中实现这一目标?
答案 0 :(得分:4)
如果您的用户拥有必要的工具(例如Visual Studio,如果他们正在编写C#类,他们应该),他们可以为您提供DLL,然后您可以加载动态:
private static T CreateInstance(string assemblyName, string typeName)
{
var assembly = Assembly.LoadFrom(assemblyName);
if (assembly == null)
throw new InvalidOperationException(
"The specified assembly '" + assemblyName + "' did not load.");
Type type = assembly.GetType(typeName);
if (type == null)
throw new InvalidOperationException(
"The specified type '" + typeName + "' was not found in assembly '" + assemblyName + "'");
return (T)Activator.CreateInstance(type);
}
存在T通用参数,以便您可以传递abstract
class
或interface
以将类型实例强制转换为:
public interface IDoSomething
{
bool DoSomething();
}
您的用户在编写自己的类时会从此界面继承:
public class UserDefinedClass : IDoSomething
{
public bool DoSomething()
{
// Implementation here.
}
}
这允许您保留类型安全性并直接调用类方法,而不是依赖于Reflection来执行此操作。
如果您真的希望用户提供C#源代码,您可以compile their class at runtime这样:
private Assembly BuildAssembly(string code)
{
var provider = new CSharpCodeProvider();
var compiler = provider.CreateCompiler();
var compilerparams = new CompilerParameters();
compilerparams.GenerateExecutable = false;
compilerparams.GenerateInMemory = true;
var results = compiler.CompileAssemblyFromSource(compilerparams, code);
if (results.Errors.HasErrors)
{
var errors = new StringBuilder("Compiler Errors :\r\n");
foreach (CompilerError error in results.Errors )
{
errors.AppendFormat("Line {0},{1}\t: {2}\n",
error.Line, error.Column, error.ErrorText);
}
throw new Exception(errors.ToString());
}
else
{
return results.CompiledAssembly;
}
}
然后,您只需在上面的CreateInstance
代码中替换生成的程序集,而不是外部加载的程序集。请注意,您的用户仍需要在其班级顶部提供相应的using
语句。
互联网上还有一些地方在C#中解释how to get an Eval()
function,以防你真的不需要一个完整的课程。