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
}
}