私は、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();
}
プラグインシステムではおそらくうまく機能しますが、すべてのルールが1つのC#ソースファイルに含まれているため、コードはそのままで1つのファイルの読み込みと実行に制限されます。ただし、実行したいファイルごとにタイプ/ソースファイルを渡すように変更するのは非常に簡単だと思います。コードをゲッターから、これら2つのパラメーターを受け取るメソッドに移動するだけです。
また、ITestRunnerの代わりにIRunnableを使用してください。
export
とimport
知られているインターフェイスから派生する別のアセンブリ内のクラス