在运行中的应用程序上添加新的cs文件

本文关键字:添加 cs 文件 程序上 应用程序 运行 应用 | 更新日期: 2023-09-27 18:18:02

我有一个命令处理程序,基本上是这样工作的:

ControlList.Handlers[CommandType.MyCommandComesHere].Handle(data);

HandlersDictionary<CommandType, ICommandHandler>, CommandType为enum。

Handle反过来会导致如下结果:

using System;
using log4net;
namespace My_Application
{
    public class MyCommand : ICommandHandler
    {
        private static readonly ILog Logger = LogManager.GetLogger(typeof(MyCommand));
        public void Handle(Events data)
        {
            Console.WriteLine("I can load cs files on the fly yay!!");
        }
    }
}

我的问题是我怎样才能使我的应用程序将编译并让我使用cs文件,而它的运行?

任何简单的例子,这将是非常感激,但不需要,只要我能得到一些指针,我需要寻找什么,因为我甚至不确定我需要什么,使这发生。

简单来说,我目前正在尝试理解如何将cs文件加载到已经编译并正在运行的应用程序中

在运行中的应用程序上添加新的cs文件

使用CodeDOM,您需要首先创建一个编译器提供程序。(您可能需要将GenerateExecutable设置为false,将GenerateInMemory设置为true。)

    var csc = new CSharpCodeProvider();
    var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, "foo.exe", true);
    parameters.GenerateExecutable = false;
    parameters.GenerateInMemory = true;

然后,您可以使用CompileAssemblyFromSource编译程序集,并从它返回CompilerResults。从这个返回的对象中,使用其CompiledAssembly属性获取对生成的程序集的引用。

    var results = csc.CompileAssemblyFromSource(parameters, "contents of the .cs file");
    var assembly = results.CompiledAssembly;

然后您可以使用反射从该程序集创建实例并调用它们的方法。

    var instance = assembly.CreateInstance("MyCommand");
    // etc...

或者,如果您只对简短的代码片段感兴趣,那么使用Roslyn可能是值得的。您需要首先创建一个ScriptEngine

var engine = new ScriptEngine();

那么你可以只在它上面Execute字符串——或者Execute<T>,如果你确信字符串中的表达式返回一个可赋值给T的类型。

var myObject = engine.Execute("1+1");
var myInt = engine.Execute<int>("1+1");
这绝对是更直接的,所以如果它符合你的目的,值得研究一下。

我已经寻找了不同的方法来实现这一点,并发现cs脚本库轻量级和可用。这里是我如何使用它的代码片段。它在应用程序域内运行cs代码,因此它假定正在编译的cs脚本来自可信源。

using CSScriptLibrary;
using csscript;
using System.CodeDom.Compiler;
using System.Reflection;
    //Method example - variable script contains cs code
    //This is used to compile cs to DLL and save DLL to a defined location
    public Assembly GetAssembly(string script, string assemblyFileName)
    {
        Assembly assembly;
        CSScript.CacheEnabled = true;            
        try
        {
            bool debugBuild = false;
#if DEBUG
            debugBuild = true;
#endif
            if (assemblyFileName == null)
                assembly = CSScript.LoadCode(script, null);
            else
                assembly = CSScript.LoadCode(script, assemblyFileName, debugBuild, null);
            return assembly;
        }
        catch (CompilerException e)
        {
            //Handle compiler exceptions
        }
    }
    /// <summary>
    /// Runs the code either form script text or precompiled DLL
    /// </summary>
    public void Run(string script)
    {
        try
        {
            string tmpPath = GetPathToDLLs();  //Path, where you store precompiled DLLs
            string assemblyFileName;
            Assembly assembly = null;
            if (Directory.Exists(tmpPath))
            {
                assemblyFileName = Path.Combine(tmpPath, GetExamScriptFileName(exam));
                if (File.Exists(assemblyFileName))
                {
                    try
                    {
                        assembly = Assembly.LoadFrom(assemblyFileName); //Načtení bez kompilace
                    }
                    catch (Exception exAssemblyLoad)
                    {
                        Tools.LogError(exAssemblyLoad.Message);
                        assembly = null;
                    }
                }
            }
            else
                assemblyFileName = null;
            //If assembly not found, compile it form script string
            if (assembly ==null) 
                assembly = GetAssembly(script, assemblyFileName);
            AsmHelper asmHelper = new AsmHelper(assembly);
            //This is how I use the compiled assembly - it depends on your actual code
            ICalculateScript calcScript = (ICalculateScript)asmHelper.CreateObject(GetExamScriptClassName(exam));
            cex = calcScript.Calculate(this, exam);
            Debug.Print("***** Calculated {0} ****", exam.ZV.ZkouskaVzorkuID);
        }
        catch (Exception e)
        {
            //handle exceptions
        }
    }