Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 动态添加新的cs文件以加载我正在运行的应用程序?_C#_.net - Fatal编程技术网

C# 动态添加新的cs文件以加载我正在运行的应用程序?

C# 动态添加新的cs文件以加载我正在运行的应用程序?,c#,.net,C#,.net,我有一个命令处理程序,基本上是这样工作的: ControlList.Handlers[CommandType.MyCommandComesHere].Handle(data); 处理程序是一个字典,命令类型是一个枚举 Handle按顺序将其引导到以下位置: using System; using log4net; namespace My_Application { public class MyCommand : ICommandHandler { priv

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

ControlList.Handlers[CommandType.MyCommandComesHere].Handle(data);
处理程序
是一个
字典
命令类型
是一个枚举

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文件加载到已经编译并正在运行的应用程序中。

使用CodeDOM,您需要首先创建。(出于您的目的,您可能需要将
GenerateExecutable
设置为
false
,并将
generateeinmemory
设置为
true
。)

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

    var results = csc.CompileAssemblyFromSource(parameters, "contents of the .cs file");
    var assembly = results.CompiledAssembly;
然后,您可以使用反射从该程序集调用方法

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

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

var engine = new ScriptEngine();
然后您可以在字符串上执行
字符串,或者如果您确信字符串中的表达式返回可分配给
T
的类型,则可以执行
字符串

var myObject = engine.Execute("1+1");
var myInt = engine.Execute<int>("1+1");
var myObject=engine.Execute(“1+1”);
var myInt=engine.Execute(“1+1”);

它肯定更直接,因此值得研究它是否符合您的目的。

我寻找了不同的方法来实现这一点,并发现cs脚本库轻量级且可用。下面是我如何使用它的代码片段。它在AppDomain中运行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
        }
    }
使用CSScriptLibrary;
使用csscript;
使用System.CodeDom.Compiler;
运用系统反思;
//方法示例-变量脚本包含cs代码
//这用于将cs编译为DLL并将DLL保存到定义的位置
公共程序集GetAssembly(字符串脚本、字符串程序集文件名)
{
装配;
CSScript.CacheEnabled=true;
尝试
{
bool-debugBuild=false;
#如果调试
debugBuild=true;
#恩迪夫
if(assemblyFileName==null)
assembly=CSScript.LoadCode(脚本,null);
其他的
assembly=CSScript.LoadCode(脚本、assemblyFileName、debugBuild、null);
返回组件;
}
捕获(编译器异常e)
{
//处理编译器异常
}
}
/// 
///以脚本文本或预编译DLL的形式运行代码
/// 
公共无效运行(字符串脚本)
{
尝试
{
字符串tmpPath=GetPathToDLLs();//路径,存储预编译DLL的位置
字符串文件名;
Assembly=null;
if(Directory.Exists(tmpPath))
{
assemblyFileName=Path.Combine(tmpPath,GetExamScriptFileName(考试));
if(File.Exists(assemblyFileName))
{
尝试
{
assembly=assembly.LoadFrom(assemblyFileName);//Načteníbez kompilace
}
捕获(异常exAssemblyLoad)
{
工具。日志错误(exAssemblyLoad.Message);
assembly=null;
}
}
}
其他的
assemblyFileName=null;
//如果未找到程序集,请将其编译为脚本字符串
if(assembly==null)
assembly=GetAssembly(脚本,assemblyFileName);
AsmHelper AsmHelper=新AsmHelper(程序集);
//这就是我如何使用编译后的程序集——这取决于您的实际代码
ICalculateScript calcScript=(ICalculateScript)asmHelper.CreateObject(GetExamScriptClassName(考试));
cex=calcScript.Calculate(本次考试);
Print(“*******计算{0}****”,exam.ZV.ZkouskaVzorkuID);
}
捕获(例外e)
{
//处理异常
}
}

cs文件从不编译,因为它是源文件。在这种情况下,您唯一能做的就是加载cs文件的内容,并在运行时编译以使用它。您可以声明一个源代码继承的接口来使用。我会在cs脚本中使用脚本宿主,或者看看它的来源以获得一些启示:@S.L.我不完全确定这需要什么过程,但我不介意它是否需要编译,只要我能够在更改代码时随意加载和重新加载特定代码,而不必关闭我的应用程序来编译新代码等等,基本上是一个接受c#的插件接口code@Guapo看看第一个答案:)这就解释了你考虑过MEF吗+1这看起来很有趣,如果我想重新加载同一个文件,那么方法和内容是缓存还是不允许我反复加载给定的文件?不,我不认为它是缓存的(但我上次使用它已经很久了,所以我可能错了)。
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
        }
    }