C #을 동적으로 컴파일,로드 및 실행하기 위해 CS-Script 를 사용하는 내 규칙 엔진에서 원하는 작업을 정확히 수행하고 있습니다 . 찾고있는 내용으로 쉽게 번역 할 수 있어야하며 예를 들어 보겠습니다. 첫째, 코드 (줄임) :
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에서이 두 매개 변수를 사용하는 메소드로 코드를 이동하면됩니다.
또한 ITestRunner 대신 IRunnable을 사용하십시오.
export및import알려진 인터페이스에서 파생 별도의 어셈블리의 클래스