对于不了解IronPhython的同学可以参考IronPython 与C#交互
一、基础知识
我们先从一个简单场景开始
不同公司的年假会有不同的策略,国家的规定好像是工作一年以上年假为5天,而有些公司还有些扩展的年假,比如每在公司多待一年年假增加1天,经理级别第一年就有年假等。如果我们使用简单的配置方式可能无法满足更复杂的策略,如果使用C#的动态编译(.net项目的二次开发解决方案)又有点复杂而且交互时还可能因为不同程序域带来很多问题。现在有了IronPhython实现起来就比较简单了。
我们先看代码:
public class Employee
{
public string Name { get; set; }
public int Id { get; set; }
public int EnterDays { get; set; }
public Position Position { get; set; }
public int AnnualLeave
{
get
{
return (int)PolicyService.GetValue(this);
}
}
}
public enum Position
{
General,
Manager
}
class PolicyService
{
public static object GetValue(object data)
{
string ironPythonExpression = string.Empty;
ironPythonExpression = @"
def MyFunction():
if(data.EnterDays>365 or data.Position==1):
return 5+data.EnterDays/365-1
else:
return 0
";
Policy policy = new Policy(ironPythonExpression);
return policy.Compute(data);
}
}
class Policy
{
private string ironPythonExpression;
public object Compute(object data)
{
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
scope.SetVariable("data", data);
var sourceCode = engine.CreateScriptSourceFromString(ironPythonExpression).Compile().Execute(scope);
var func = engine.GetVariable<Func<object>>(scope, "MyFunction");
return func();
}
public Policy(string ironPythonExpression)
{
this.ironPythonExpression = ironPythonExpression;
}
}
class Program
{
static void Main(string[] args)
{
Employee employee = new Employee() {Id=1, EnterDays = 800,Name="lfm" };
Console.WriteLine(employee.AnnualLeave);
}
}
结果为6
这里我们可以将ironPythonExpression中的内容存在数据库中,根据我们的策略进行修改,因为这里是ironPython的源代码,所以你扩展策略逻辑的自由度会非常大
二、策略中心设计示意
SQLServer2008中有策略管理(可以参考SQL Server 2008新特性——策略管理 ),我们这里要做的策略中心跟这个有些相似,首先我们先介绍一下我们要用到的三个术语
1、方面:方面就是策略要应用的对象,比如员工年假,员工号
2、条件:条件就是一个布尔表达式判断策略是否为真
3、策略:策略就是在条件为假的情况下要执行的操作
我们先来看代码:
namespace ConsoleApplication7
{
public class Employee
{
public string Name { get; set; }
public int Id { get; set; }
public int EnterDays { get; set; }
public Position Position { get; set; }
public int AnnualLeave
{
get
{
Aspect aspect = new Aspect() { InputeType = typeof(Employee), OutputType = typeof(int), AspectEnum = AspectEnum.AnnualLeave };
return (int)PolicyService.GetValue(aspect, this);
}
}
public string GetEmployeeNum()
{
Aspect aspect = new Aspect() { InputeType = typeof(Employee), OutputType = typeof(string), AspectEnum = AspectEnum.EmployeeNum };
return (string)PolicyService.GetValue(aspect, this);
}
}
public enum Position
{
General,
Manager
}
}
namespace ConsoleApplication7
{
class PolicyService
{
public static object GetValue(Aspect aspect, object data)
{
string ironPythonExpression = string.Empty;
if (aspect.AspectEnum == AspectEnum.AnnualLeave)
{
ironPythonExpression = @"
def MyFunction():
if(data.EnterDays>365 or data.Position==1):
return 5+data.EnterDays/365-1
else:
return 0
";
}
else if (aspect.AspectEnum == AspectEnum.EmployeeNum)
{
ironPythonExpression = @"
def MyFunction():
return data.Name+str(data.Id)
";
}
Policy policy = new Policy(ironPythonExpression);
return policy.Compute(data);
}
}
class Policy
{
private string ironPythonExpression;
public object Compute(object data)
{
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
scope.SetVariable("data", data);
var sourceCode = engine.CreateScriptSourceFromString(ironPythonExpression).Compile().Execute(scope);
var func = engine.GetVariable<Func<object>>(scope, "MyFunction");
return func();
}
public Policy(string ironPythonExpression)
{
this.ironPythonExpression = ironPythonExpression;
}
}
}
namespace ConsoleApplication7
{
public class Aspect
{
public Type InputeType { set; get; }
public Type OutputType { get; set; }
public AspectEnum AspectEnum { get; set; }
}
public enum AspectEnum
{
AnnualLeave,
EmployeeNum
}
}
namespace ConsoleApplication7
{
class Program
{
static void Main(string[] args)
{
Employee employee = new Employee() {Id=1, EnterDays = 800,Name="lfm" };
Console.WriteLine(employee.AnnualLeave);
Console.WriteLine(employee.GetEmployeeNum());
}
}
}
结果为
6
lfm1
这里只是实现策略中心的部分核心代码,如果真的实现这个策略中心的话还有很多辅助工作要做,这里边IronPhython代码可能需要我们提供界面生成出来,那么我们就需要在使用的地方为策略服务提供输入和返回的数据类型,策略服务可以根据输入类型来反射得到所有的字段,这些字段可以用于生成条件,然后这些条件可以用来生成IronPhython代码,也可以把这些字段应用到IronPhython代码编写相应的策略上。
源码下载(需要自己引用IronPython)