【问题标题】:Compiling and accessing class at runtime [closed]在运行时编译和访问类[关闭]
【发布时间】:2012-04-03 04:01:10
【问题描述】:

我正在尝试向我的应用程序添加一些特定的模块化功能,我需要用户能够创建自己的类,然后在运行时将它们导入到程序中,这些类将遵循特定的模板,因此我可以调用函数在他们的新班级中。

例如,一个类可以是:http://pastebin.com/90NTjia9

我会编译类然后执行 doSomething();

如何在 C# 中实现这一点?

【问题讨论】:

  • 通常您会通过向用户提供一个 dll 来实现此目的,该 dll 提供了您的应用程序的挂钩。这使他们能够创建一个 dll,然后您的应用可以加载该 dll。
  • 我使用的程序可以让您简单地将 .cs 文件拖放到目录中,然后编译并运行它。
  • 在这里查看 Darin Dimitrov 的回答:stackoverflow.com/questions/4718329/…
  • 您可以查看 LINQPad 的工作原理:linqpad.net/HowLINQPadWorks.aspx。不完全一样,因为用户在 LINQPad 的 UI 中键入代码。

标签: c# winforms console runtime


【解决方案1】:

如果您的用户拥有必要的工具(例如 Visual Studio,如果他们正在编写 C# 类,他们确实应该拥有),他们可以为您提供一个 DLL,然后您可以加载该 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 classinterface 将类型实例强制转换为:

public interface IDoSomething
{
    bool DoSomething();
}

您的用户在编写自己的类时从该接口继承:

public class UserDefinedClass : IDoSomething
{
    public bool DoSomething()
    {
        // Implementation here.
    }
}

这允许您保持类型安全并直接调用类方法,而不是依赖反射来这样做。

如果你真的希望你的用户提供 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,以防你真的不需要完整的课程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-31
    • 1970-01-01
    相关资源
    最近更新 更多