Dinamik olarak derlemek, yüklemek ve C # çalıştırmak için CS-Script kullanan kural motorumda tam olarak aradığınız şeyi yapıyorum . Aradığınız şeye kolayca çevrilebilir ve bir örnek vereceğim. İlk olarak, kod (soyulmuş):
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;
}
}
}
Bu, T tipi bir arabirimi alır, bir .cs dosyasını bir derlemede derler, belirli bir türdeki bir sınıfı başlatır ve bu başlatılan sınıfı T arabirimiyle hizalar. Temel olarak, yalnızca başlatılan sınıfın bu arabirimi uyguladığından emin olmanız gerekir. Her şeyi kurmak ve erişmek için özellikleri kullanıyorum, örneğin:
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; }
}
Örneğiniz için, Run () 'ı çağırmak istiyorsunuz, bu nedenle Run () yöntemini tanımlayan bir arabirim oluşturabilirim, örneğin:
public interface ITestRunner
{
void Run();
}
Ardından, aşağıdaki gibi uygulayan bir sınıf oluşturun:
public class TestRunner : ITestRunner
{
public void Run()
{
}
}
RulesEngine'in adını TestHarness gibi bir şeye değiştirin ve özelliklerinizi ayarlayın:
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; }
}
Ardından, onu aramak istediğiniz her yerde koşabilirsiniz:
ITestRunner testRunner = TestHarnessInterface;
if (null != testRunner)
{
testRunner.Run();
}
Muhtemelen bir eklenti sistemi için harika çalışır, ancak benim kodum olduğu gibi bir dosyanın yüklenmesi ve çalıştırılmasıyla sınırlıdır, çünkü tüm kurallarımız tek bir C # kaynak dosyasındadır. Yine de çalıştırmak istediğiniz her biri için tür / kaynak dosyasını geçirmek için onu değiştirmenin oldukça kolay olacağını düşünürdüm. Kodu alıcıdan bu iki parametreyi alan bir yönteme taşımanız yeterlidir.
Ayrıca, ITestRunner yerine IRunnable'ınızı kullanın.
export
veimport
sınıflar, bilinen bir arayüzden türetilen ayrı derlemelerde