我正在完全按照您在我的规则引擎中寻找的内容进行操作,该引擎使用CS-Script动态编译,加载和运行C#。它应该可以轻松转换为您要查找的内容,我将举一个例子。首先,代码(向下精简):
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using CSScriptLibrary;
namespace RulesEngine
{
public class RulesEngine<T> where T : class
{
public RulesEngine(string rulesScriptFileName, string classToInstantiate)
: this()
{
if (rulesScriptFileName == null) throw new ArgumentNullException("rulesScriptFileName");
if (classToInstantiate == null) throw new ArgumentNullException("classToInstantiate");
if (!File.Exists(rulesScriptFileName))
{
throw new FileNotFoundException("Unable to find rules script", rulesScriptFileName);
}
RulesScriptFileName = rulesScriptFileName;
ClassToInstantiate = classToInstantiate;
LoadRules();
}
public T @Interface;
public string RulesScriptFileName { get; private set; }
public string ClassToInstantiate { get; private set; }
public DateTime RulesLastModified { get; private set; }
private RulesEngine()
{
@Interface = null;
}
private void LoadRules()
{
if (!File.Exists(RulesScriptFileName))
{
throw new FileNotFoundException("Unable to find rules script", RulesScriptFileName);
}
FileInfo file = new FileInfo(RulesScriptFileName);
DateTime lastModified = file.LastWriteTime;
if (lastModified == RulesLastModified)
{
return;
}
string rulesScript = File.ReadAllText(RulesScriptFileName);
Assembly compiledAssembly = CSScript.LoadCode(rulesScript, null, true);
@Interface = compiledAssembly.CreateInstance(ClassToInstantiate).AlignToInterface<T>();
RulesLastModified = lastModified;
}
}
}
这将采用类型T的接口,将.cs文件编译为程序集,实例化给定类型的类,并将该实例化的类与T接口对齐。基本上,您只需要确保实例化的类实现了该接口。我使用属性来设置和访问所有内容,例如:
private RulesEngine<IRulesEngine> rulesEngine;
public RulesEngine<IRulesEngine> RulesEngine
{
get
{
if (null == rulesEngine)
{
string rulesPath = Path.Combine(Application.StartupPath, "Rules.cs");
rulesEngine = new RulesEngine<IRulesEngine>(rulesPath, typeof(Rules).FullName);
}
return rulesEngine;
}
}
public IRulesEngine RulesEngineInterface
{
get { return RulesEngine.Interface; }
}
对于您的示例,您想调用Run(),因此我将创建一个定义Run()方法的接口,如下所示:
public interface ITestRunner
{
void Run();
}
然后创建一个实现它的类,如下所示:
public class TestRunner : ITestRunner
{
public void Run()
{
}
}
将RulesEngine的名称更改为TestHarness,然后设置属性:
private TestHarness<ITestRunner> testHarness;
public TestHarness<ITestRunner> TestHarness
{
get
{
if (null == testHarness)
{
string sourcePath = Path.Combine(Application.StartupPath, "TestRunner.cs");
testHarness = new TestHarness<ITestRunner>(sourcePath , typeof(TestRunner).FullName);
}
return testHarness;
}
}
public ITestRunner TestHarnessInterface
{
get { return TestHarness.Interface; }
}
然后,在任何要调用它的地方都可以运行:
ITestRunner testRunner = TestHarnessInterface;
if (null != testRunner)
{
testRunner.Run();
}
这对于一个插件系统可能会很好用,但是我的代码原样仅限于加载和运行一个文件,因为我们所有的规则都在一个C#源文件中。我想修改它很容易,只需为要运行的每个文件传入类型/源文件即可。您只需要将代码从getter移到采用这两个参数的方法即可。
另外,使用IRunnable代替ITestRunner。
export
和import
来自已知接口的单独程序集中的类