C# 在运行时编译和访问类
我正在尝试向我的应用程序添加一些特定的模块功能,我需要用户能够创建自己的类,然后在运行时将它们导入到程序中,这些类将遵循特定的模板,以便我可以在新类中调用函数 例如,一个类可以是: 我会编译这个类,然后执行doSomethingC# 在运行时编译和访问类,c#,winforms,console,runtime,C#,Winforms,Console,Runtime,我正在尝试向我的应用程序添加一些特定的模块功能,我需要用户能够创建自己的类,然后在运行时将它们导入到程序中,这些类将遵循特定的模板,以便我可以在新类中调用函数 例如,一个类可以是: 我会编译这个类,然后执行doSomething 如何在C中实现这一点?如果您的用户拥有必要的工具,如Visual Studio,如果他们正在编写C类,他们就应该拥有这些工具,他们可以为您提供DLL,然后您可以动态加载: private static T CreateInstance(string assemblyNa
如何在C中实现这一点?如果您的用户拥有必要的工具,如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 generic参数,因此您可以传递抽象类或接口以将类型实例强制转换为:
public interface IDoSomething
{
bool DoSomething();
}
用户在编写自己的类时从该接口继承:
public class UserDefinedClass : IDoSomething
{
public bool DoSomething()
{
// Implementation here.
}
}
这允许您保留类型安全性并直接调用类方法,而不是依赖反射来实现
如果您确实希望用户提供C源代码,您可以这样做:
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语言解释,以防你真的不需要一个完整的类。如果你的用户有必要的工具,如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 generic参数,因此您可以传递抽象类或接口以将类型实例强制转换为:
public interface IDoSomething
{
bool DoSomething();
}
用户在编写自己的类时从该接口继承:
public class UserDefinedClass : IDoSomething
{
public bool DoSomething()
{
// Implementation here.
}
}
这允许您保留类型安全性并直接调用类方法,而不是依赖反射来实现
如果您确实希望用户提供C源代码,您可以这样做:
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语句
Internet上也有一些地方用C语言解释,以防您真的不需要一个完整的类。通常,您可以通过向用户提供一个dll来实现这一点,该dll为您的应用程序提供挂钩。这使他们能够创建一个dll,然后您的应用程序可以加载该dll。我使用了一些程序,让您只需将一个.cs文件放到一个目录中,并对其进行编译和运行。请参见Darin Dimitrov的回答:您可以查看LINQPad的工作原理:。不完全一样,因为用户在LINQPad的UI中键入代码。通常,您可以通过向用户提供一个dll来实现这一点,该dll为您的应用程序提供挂钩。这使他们能够创建一个dll,然后您的应用程序可以加载该dll。我使用了一些程序,让您只需将一个.cs文件放到一个目录中,并对其进行编译和运行。请参见Darin Dimitrov的回答:您可以查看LINQPad的工作原理:。不完全一样,因为用户在LINQPad的UI中键入代码。