这次说解析器,像所有最基础的操作一样,解析器的最终目的是为了返回需要的值,而通过读取配置文件到引擎而获得的这些数据还不能马上用于操作,通过解析器内部的 方法集,返回对类型的判断,或对四则运算的命令作出相应,这里要说一说优先度的问题,按照优先度的由低到高依次调用调用,如:在加减法方法中调用乘方法,在乘方方法中调用成除运算,而后是正负符号运算,括号预算,每种方法中都会带一个默认为的”0”的参数,如果当真有操作,这个零值就会被替代,再巧妙的运用任何数的0次方都是1来避免除零的出现的同时,类似递归的把所有运算操作都完成了一遍。解析器这里起个专业名叫表达式状态机。
public class ExpressionMachine
{
Instance data membersInstance data members#region Instance data members
private VariableEngine m_oVarEngine;
int type = 0;
char[] expr;
int pos = 0;
char[] token;
double result;
bool bResult;
string strResult;
bool bIsStringCompare = false;
bool bNoOperator = false;
/**//**//**//// <summary>
/// This is the internal list of variables
/// </summary>
public ArrayList variables = new ArrayList();
/**//**//**//// <summary>
/// Enumeration of Result Types
/// </summary>
public enum ResultType
{
/**//**//**//// <summary>
/// Default enum value
/// </summary>
NONE,
/**//**//**//// <summary>
/// ResultType as Boolean
/// </summary>
BOOL,
/**//**//**//// <summary>
/// ResultType as Double
/// </summary>
DOUBLE,
/**//**//**//// <summary>
/// ResultType as String
/// </summary>
STRING
}
/**//**//**//// <summary>
/// The Result type of the expression.
/// </summary>
ResultType resType = ResultType.NONE;
/**//**//**//// <summary>
///
/// </summary>
const int NONE = 0;
/**//**//**//// <summary>
///
/// </summary>
const int VAR = 1;
const int DEL = 2;
const int NUM = 3;
StringBuilder errors;
#endregion
CtorsCtors#region Ctors
/**//**//**//// <summary>
/// Default constructor
/// </summary>
public ExpressionMachine()
{
result = 0;
bResult = false;
strResult = "";
System.Console.WriteLine("ExpressionMachine by JaxLab.com");
}
#endregion
is 'a' methodsis 'a' methods#region is 'a' methods
private bool isWhite(char c)
{
if(c == ' ' || c == '\t')
{
return true;
}
else
{
return false;
}
}
private bool isNumeric(char c)
{
if((c >= '0' && c <= '9') || c == '.')
{
return true;
}
else
{
return false;
}
}
private bool isAlpha(char c)
{
if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '.'|| c == ',')
{
return true;
}
else
{
return false;
}
}
private bool isMinus(char c)
{
if(c == '-')
{
return true;
}
else
{
return false;
}
}
private bool isDelimiter(char c)
{
if(c == '+' || c == '-' || c == '*' || c == '/' ||
c == '%' || c == '^' || c == '(' || c == ')' ||
c == ',' || c == '=')
{
return true;
}
else
{
return false;
}
}
private bool isComparator(char c)
{
if(c == '<' || c == '>' || c =='=' || c == '!')
{
return true;
}
else
{
return false;
}
}
#endregion
Math functionsMath functions#region Math functions
private double deg(double x)
{
return (180.0 / Math.PI) * x;
}
private double rad(double x)
{
return (Math.PI / 180.0) * x;
}
#endregion
Evaluation functionsEvaluation functions#region Evaluation functions
/**//**//**//// <summary>
/// This is the method to call to run the expression machine.
/// </summary>
/// <param name="stre">the string that is the expression</param>
/// <param name="oVarEngine">the variable engine to get variables from</param>
public void Resolve(string stre, VariableEngine oVarEngine)
{
this.m_oVarEngine = oVarEngine;
stre = stre.Replace(" and ", " & ");
stre = stre.Replace(" or ", " | ");
stre = stre.Replace("\r", " ");
stre = stre.Replace("\n", " ");
stre = stre.Trim();
string sCompCheck = StripAttrs(stre);
if(this.isComparison(sCompCheck) || this.isCompoundComparison(sCompCheck))
{
this.resType = ResultType.BOOL;
}
else if(this.HasOperator(sCompCheck))
{
this.resType = ResultType.DOUBLE;
}
else
{
double d;
if(Utilities.StringToDouble(stre, out d))
{
this.resType = ResultType.DOUBLE;
}
else
{
this.resType = ResultType.STRING;
}
}
if(stre.IndexOf("R[*]") > 0)
{
// char[] spaces = {' '};
// string sWithAttrs = this.NormalizeAttrSpaces(stre, true);
// string[] strs = sWithAttrs.Split(spaces);
// for(int i = 0; i < strs.Length; i++)
// {
// if(strs[i].IndexOf("R[*]") > 0)
// {
// string varName = this.StripAttrs(strs[i]);
// string sAttr = this.GetAttrs(strs[i]);
//
// Variable var = this.m_oVarEngine.Find(varName);
// if(var is VariableDataset)
// {
// VariableDataset vds = var as VariableDataset;
// }
// }
// }
}
else
{
Evaluate(stre);
}
}
private void Evaluate(string stre)
{
try
{
result = 0;
pos = 0;
this.strResult = "";
this.bResult = false;
errors = new StringBuilder();
string se = stre.Trim();
string e = GetAttrValues(se);
if(!HasOperator(e))
{
this.bNoOperator = true;
Variable var = null;
string sVarAttr = string.Empty;
if(e.IndexOf(".") > 0)
{
int iNdx = e.IndexOf(".");
string sVarName = e.Substring(0, iNdx);
sVarAttr = e.Substring(iNdx + 1);
var = m_oVarEngine.Find(sVarName);
}
else
{
var = m_oVarEngine.Find(e);
}
if(var == null)
{
expr = e.ToCharArray();
Parse();
if (this.type == NUM && Utilities.IsANumber(e))
{
this.result = double.Parse(e);
this.strResult = "" + result;
if (result < 0)
{
this.bResult = false;
}
else
{
this.bResult = true;
}
}
else
{
this.strResult = e;
this.result = 0;
if (strResult.Length > 0)
{
this.bResult = true;
}
else
{
this.bResult = false;
}
}
}
else
{
if(var.VarType == Variable.VariableType.TEXT)
{
bIsStringCompare = true;
result = var.DoubleValue;
bResult = var.BoolValue;
strResult = var.StringValue;
}
else if(var.VarType == Variable.VariableType.OBJECT)
{
//IVariableObject oIVar = var.ObjectValue as IVariableObject;
object res = var.GetAttribute(sVarAttr);
Variable oResVar = new Variable("", "" + res);
result = oResVar.DoubleValue;
bResult = oResVar.BoolValue;
strResult = oResVar.StringValue;
}
else
{
bIsStringCompare = false;
result = var.DoubleValue;
bResult = var.BoolValue;
strResult = var.StringValue;
}
}
}
else if(isCompoundComparison(e))
{
this.bNoOperator = false;
if(processComparison(e))
{
result = 1;
bResult = true;
}
else
{
result = 0;
bResult = false;
}
}
else if(isComparison(e))
{
this.bNoOperator = false;
if(this.Compare(e))
{
result = 1;
bResult = true;
}
else
{
result = 0;
bResult = false;
}
}
else
{
this.bNoOperator = false;
string etmp = e + "~";
expr = etmp.ToCharArray();
if (e.IndexOf("[") > -1)
{
}
else
{
while (this.pos < expr.Length - 1)
{
Parse();
assignment(ref result);
}
}
}
}
catch(Exception re)
{
errors.Append("Error in Evaluate: " + re.Message + re.StackTrace);
}
}
private string NormalizeAttrSpaces(string str, bool bUnderscore)
{
StringBuilder sb = new StringBuilder();
char[] chars = str.ToCharArray();
bool isDot = false;
bool isOpen = false;
bool isClose = false;
for (int i = 0; i < chars.Length; i++)
{
char c = chars[i];
if (c == '.')
{
isDot = true;
}
if (c == '[')
{
isOpen = true;
}
if (c == ']')
{
isClose = true;
isOpen = false;
}
if (isClose && c == ' ')
{
isDot = false;
isClose = false;
}
if (bUnderscore)
{
if (isOpen && c == ' ')
{
sb.Append('_');
}
else
{
sb.Append(c);
}
}
else
{
if (isOpen && c == '_')
{
sb.Append(' ');
}
else
{
sb.Append(c);
}
}
}
return sb.ToString();
}
private string GetAttrValues(string str)
{
if (Utilities.IsANumber(str))
{
return str;
}
if (str.IndexOf(".") > 0)
{
int iNameNdx = str.IndexOf(".");
string sVarNameChk = str.Substring(0, iNameNdx);
Variable varchk = m_oVarEngine.Find(sVarNameChk);
if (varchk == null)
{
return str;
}
string aStr = NormalizeAttrSpaces(str, true);
StringBuilder sb = new StringBuilder();
char[] space = { ' ' };
string[] strs = aStr.Split(space);
foreach (string s in strs)
{
if (s.IndexOf(".") > 0)
{
string sOpStr = NormalizeAttrSpaces(s, false);
int iDot = sOpStr.IndexOf(".");
string varName = sOpStr.Substring(0, iDot);
string attr = sOpStr.Substring(iDot + 1);
Variable var = m_oVarEngine.Find(varName);
if (var != null)
{
object obj = var.GetAttribute(attr);
sb.Append(obj + " ");
}
else
{
sb.Append(0 + " ");
}
}
else
{
sb.Append(s + " ");
}
}
return sb.ToString().Trim();
}
else
{
return str;
}
}
private string StripAttrs(string str)
{
StringBuilder sb = new StringBuilder();
char[] chars = str.ToCharArray();
bool isDot = false;
bool isOpen = false;
bool isClose = false;
for (int i = 0; i < chars.Length; i++)
{
char c = chars[i];
if (c == '.')
{
isDot = true;
}
if (c == '[')
{
isOpen = true;
}
if (c == ']')
{
isClose = true;
isOpen = false;
}
if (isClose && c == ' ')
{
isDot = false;
isClose = false;
}
if(!isDot)
{
sb.Append(c);
}
}
return sb.ToString();
}
private string GetAttrs(string str)
{
StringBuilder sb = new StringBuilder();
char[] chars = str.ToCharArray();
bool isDot = false;
bool isOpen = false;
bool isClose = false;
for (int i = 0; i < chars.Length; i++)
{
char c = chars[i];
if (c == '.')
{
isDot = true;
}
if (c == '[')
{
isOpen = true;
}
if (c == ']')
{
isClose = true;
isOpen = false;
}
if (isClose && c == ' ')
{
isDot = false;
isClose = false;
}
if(isDot)
{
sb.Append(c);
}
}
return sb.ToString();
}
private bool IsOperator(char c)
{
bool bRet = false;
string s = new string(c, 1);
string[] ops = { "+", "-", "/", "*", "%", "|", "&", "isa", "hasa" };
foreach (string str in ops)
{
if (s.CompareTo(str) == 0)
{
bRet = true;
break;
}
}
return bRet;
}
/**//**//**//// <summary>
/// Loads and resolves a comparison string
/// </summary>
/// <param name="expr">the expression as a string</param>
/// <returns>the result of the comparison (true or false)</returns>
public bool Compare(string expr)
{
try
{
if(expr.IndexOf("<=") > 0)
{
int ndx = expr.IndexOf("<=");
string lstr = expr.Substring(0, ndx);
string rstr = expr.Substring(ndx + 2);
Evaluate(lstr);
double lval = result;
Evaluate(rstr);
double rval = result;
if(lval <= rval)
{
return true;
}
else
{
return false;
}
}
else if(expr.IndexOf(">=") > 0)
{
int ndx = expr.IndexOf(">=");
string lstr = expr.Substring(0, ndx);
string rstr = expr.Substring(ndx + 2);
Evaluate(lstr);
double lval = result;
Evaluate(rstr);
double rval = result;
if(lval >= rval)
{
return true;
}
else
{
return false;
}
}
else if(expr.IndexOf("!=") > 0)
{
int ndx = expr.IndexOf("!=");
string lstr = expr.Substring(0, ndx);
string rstr = expr.Substring(ndx + 2);
if(rstr.IndexOf("\"") > -1)
{
Variable var = m_oVarEngine.Find(lstr);
string strTrim = rstr.Trim();
string strSub = strTrim.Substring(1, strTrim.Length - 2);
if(var.StringValue.CompareTo(strSub) == 0)
{
return false;
}
else
{
return true;
}
}
else
{
Evaluate(lstr);
double lval = result;
Evaluate(rstr);
double rval = result;
if(lval != rval)
{
return true;
}
else
{
return false;
}
}
}
else if(expr.IndexOf("<") > 0)
{
int ndx = expr.IndexOf("<");
string lstr = expr.Substring(0, ndx);
string rstr = expr.Substring(ndx + 1);
Evaluate(lstr);
double lval = result;
Evaluate(rstr);
double rval = result;
if(lval < rval)
{
return true;
}
else
{
return false;
}
}
else if(expr.IndexOf(">") > 0)
{
int ndx = expr.IndexOf(">");
string lstr = expr.Substring(0, ndx);
string rstr = expr.Substring(ndx + 1);
Evaluate(lstr.Trim());
double lval = result;
Evaluate(rstr.Trim());
double rval = result;
<img src="http://
说到这里外围的这些都已经介绍到了,现在就来看看核心的构造吧{
Instance data membersInstance data members#region Instance data members
private VariableEngine m_oVarEngine;
int type = 0;
char[] expr;
int pos = 0;
char[] token;
double result;
bool bResult;
string strResult;
bool bIsStringCompare = false;
bool bNoOperator = false;
/**//**//**//// <summary>
/// This is the internal list of variables
/// </summary>
public ArrayList variables = new ArrayList();
/**//**//**//// <summary>
/// Enumeration of Result Types
/// </summary>
public enum ResultType
{
/**//**//**//// <summary>
/// Default enum value
/// </summary>
NONE,
/**//**//**//// <summary>
/// ResultType as Boolean
/// </summary>
BOOL,
/**//**//**//// <summary>
/// ResultType as Double
/// </summary>
DOUBLE,
/**//**//**//// <summary>
/// ResultType as String
/// </summary>
STRING
}
/**//**//**//// <summary>
/// The Result type of the expression.
/// </summary>
ResultType resType = ResultType.NONE;
/**//**//**//// <summary>
///
/// </summary>
const int NONE = 0;
/**//**//**//// <summary>
///
/// </summary>
const int VAR = 1;
const int DEL = 2;
const int NUM = 3;
StringBuilder errors;
#endregion
CtorsCtors#region Ctors
/**//**//**//// <summary>
/// Default constructor
/// </summary>
public ExpressionMachine()
{
result = 0;
bResult = false;
strResult = "";
System.Console.WriteLine("ExpressionMachine by JaxLab.com");
}
#endregion
is 'a' methodsis 'a' methods#region is 'a' methods
private bool isWhite(char c)
{
if(c == ' ' || c == '\t')
{
return true;
}
else
{
return false;
}
}
private bool isNumeric(char c)
{
if((c >= '0' && c <= '9') || c == '.')
{
return true;
}
else
{
return false;
}
}
private bool isAlpha(char c)
{
if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '.'|| c == ',')
{
return true;
}
else
{
return false;
}
}
private bool isMinus(char c)
{
if(c == '-')
{
return true;
}
else
{
return false;
}
}
private bool isDelimiter(char c)
{
if(c == '+' || c == '-' || c == '*' || c == '/' ||
c == '%' || c == '^' || c == '(' || c == ')' ||
c == ',' || c == '=')
{
return true;
}
else
{
return false;
}
}
private bool isComparator(char c)
{
if(c == '<' || c == '>' || c =='=' || c == '!')
{
return true;
}
else
{
return false;
}
}
#endregion
Math functionsMath functions#region Math functions
private double deg(double x)
{
return (180.0 / Math.PI) * x;
}
private double rad(double x)
{
return (Math.PI / 180.0) * x;
}
#endregion
Evaluation functionsEvaluation functions#region Evaluation functions
/**//**//**//// <summary>
/// This is the method to call to run the expression machine.
/// </summary>
/// <param name="stre">the string that is the expression</param>
/// <param name="oVarEngine">the variable engine to get variables from</param>
public void Resolve(string stre, VariableEngine oVarEngine)
{
this.m_oVarEngine = oVarEngine;
stre = stre.Replace(" and ", " & ");
stre = stre.Replace(" or ", " | ");
stre = stre.Replace("\r", " ");
stre = stre.Replace("\n", " ");
stre = stre.Trim();
string sCompCheck = StripAttrs(stre);
if(this.isComparison(sCompCheck) || this.isCompoundComparison(sCompCheck))
{
this.resType = ResultType.BOOL;
}
else if(this.HasOperator(sCompCheck))
{
this.resType = ResultType.DOUBLE;
}
else
{
double d;
if(Utilities.StringToDouble(stre, out d))
{
this.resType = ResultType.DOUBLE;
}
else
{
this.resType = ResultType.STRING;
}
}
if(stre.IndexOf("R[*]") > 0)
{
// char[] spaces = {' '};
// string sWithAttrs = this.NormalizeAttrSpaces(stre, true);
// string[] strs = sWithAttrs.Split(spaces);
// for(int i = 0; i < strs.Length; i++)
// {
// if(strs[i].IndexOf("R[*]") > 0)
// {
// string varName = this.StripAttrs(strs[i]);
// string sAttr = this.GetAttrs(strs[i]);
//
// Variable var = this.m_oVarEngine.Find(varName);
// if(var is VariableDataset)
// {
// VariableDataset vds = var as VariableDataset;
// }
// }
// }
}
else
{
Evaluate(stre);
}
}
private void Evaluate(string stre)
{
try
{
result = 0;
pos = 0;
this.strResult = "";
this.bResult = false;
errors = new StringBuilder();
string se = stre.Trim();
string e = GetAttrValues(se);
if(!HasOperator(e))
{
this.bNoOperator = true;
Variable var = null;
string sVarAttr = string.Empty;
if(e.IndexOf(".") > 0)
{
int iNdx = e.IndexOf(".");
string sVarName = e.Substring(0, iNdx);
sVarAttr = e.Substring(iNdx + 1);
var = m_oVarEngine.Find(sVarName);
}
else
{
var = m_oVarEngine.Find(e);
}
if(var == null)
{
expr = e.ToCharArray();
Parse();
if (this.type == NUM && Utilities.IsANumber(e))
{
this.result = double.Parse(e);
this.strResult = "" + result;
if (result < 0)
{
this.bResult = false;
}
else
{
this.bResult = true;
}
}
else
{
this.strResult = e;
this.result = 0;
if (strResult.Length > 0)
{
this.bResult = true;
}
else
{
this.bResult = false;
}
}
}
else
{
if(var.VarType == Variable.VariableType.TEXT)
{
bIsStringCompare = true;
result = var.DoubleValue;
bResult = var.BoolValue;
strResult = var.StringValue;
}
else if(var.VarType == Variable.VariableType.OBJECT)
{
//IVariableObject oIVar = var.ObjectValue as IVariableObject;
object res = var.GetAttribute(sVarAttr);
Variable oResVar = new Variable("", "" + res);
result = oResVar.DoubleValue;
bResult = oResVar.BoolValue;
strResult = oResVar.StringValue;
}
else
{
bIsStringCompare = false;
result = var.DoubleValue;
bResult = var.BoolValue;
strResult = var.StringValue;
}
}
}
else if(isCompoundComparison(e))
{
this.bNoOperator = false;
if(processComparison(e))
{
result = 1;
bResult = true;
}
else
{
result = 0;
bResult = false;
}
}
else if(isComparison(e))
{
this.bNoOperator = false;
if(this.Compare(e))
{
result = 1;
bResult = true;
}
else
{
result = 0;
bResult = false;
}
}
else
{
this.bNoOperator = false;
string etmp = e + "~";
expr = etmp.ToCharArray();
if (e.IndexOf("[") > -1)
{
}
else
{
while (this.pos < expr.Length - 1)
{
Parse();
assignment(ref result);
}
}
}
}
catch(Exception re)
{
errors.Append("Error in Evaluate: " + re.Message + re.StackTrace);
}
}
private string NormalizeAttrSpaces(string str, bool bUnderscore)
{
StringBuilder sb = new StringBuilder();
char[] chars = str.ToCharArray();
bool isDot = false;
bool isOpen = false;
bool isClose = false;
for (int i = 0; i < chars.Length; i++)
{
char c = chars[i];
if (c == '.')
{
isDot = true;
}
if (c == '[')
{
isOpen = true;
}
if (c == ']')
{
isClose = true;
isOpen = false;
}
if (isClose && c == ' ')
{
isDot = false;
isClose = false;
}
if (bUnderscore)
{
if (isOpen && c == ' ')
{
sb.Append('_');
}
else
{
sb.Append(c);
}
}
else
{
if (isOpen && c == '_')
{
sb.Append(' ');
}
else
{
sb.Append(c);
}
}
}
return sb.ToString();
}
private string GetAttrValues(string str)
{
if (Utilities.IsANumber(str))
{
return str;
}
if (str.IndexOf(".") > 0)
{
int iNameNdx = str.IndexOf(".");
string sVarNameChk = str.Substring(0, iNameNdx);
Variable varchk = m_oVarEngine.Find(sVarNameChk);
if (varchk == null)
{
return str;
}
string aStr = NormalizeAttrSpaces(str, true);
StringBuilder sb = new StringBuilder();
char[] space = { ' ' };
string[] strs = aStr.Split(space);
foreach (string s in strs)
{
if (s.IndexOf(".") > 0)
{
string sOpStr = NormalizeAttrSpaces(s, false);
int iDot = sOpStr.IndexOf(".");
string varName = sOpStr.Substring(0, iDot);
string attr = sOpStr.Substring(iDot + 1);
Variable var = m_oVarEngine.Find(varName);
if (var != null)
{
object obj = var.GetAttribute(attr);
sb.Append(obj + " ");
}
else
{
sb.Append(0 + " ");
}
}
else
{
sb.Append(s + " ");
}
}
return sb.ToString().Trim();
}
else
{
return str;
}
}
private string StripAttrs(string str)
{
StringBuilder sb = new StringBuilder();
char[] chars = str.ToCharArray();
bool isDot = false;
bool isOpen = false;
bool isClose = false;
for (int i = 0; i < chars.Length; i++)
{
char c = chars[i];
if (c == '.')
{
isDot = true;
}
if (c == '[')
{
isOpen = true;
}
if (c == ']')
{
isClose = true;
isOpen = false;
}
if (isClose && c == ' ')
{
isDot = false;
isClose = false;
}
if(!isDot)
{
sb.Append(c);
}
}
return sb.ToString();
}
private string GetAttrs(string str)
{
StringBuilder sb = new StringBuilder();
char[] chars = str.ToCharArray();
bool isDot = false;
bool isOpen = false;
bool isClose = false;
for (int i = 0; i < chars.Length; i++)
{
char c = chars[i];
if (c == '.')
{
isDot = true;
}
if (c == '[')
{
isOpen = true;
}
if (c == ']')
{
isClose = true;
isOpen = false;
}
if (isClose && c == ' ')
{
isDot = false;
isClose = false;
}
if(isDot)
{
sb.Append(c);
}
}
return sb.ToString();
}
private bool IsOperator(char c)
{
bool bRet = false;
string s = new string(c, 1);
string[] ops = { "+", "-", "/", "*", "%", "|", "&", "isa", "hasa" };
foreach (string str in ops)
{
if (s.CompareTo(str) == 0)
{
bRet = true;
break;
}
}
return bRet;
}
/**//**//**//// <summary>
/// Loads and resolves a comparison string
/// </summary>
/// <param name="expr">the expression as a string</param>
/// <returns>the result of the comparison (true or false)</returns>
public bool Compare(string expr)
{
try
{
if(expr.IndexOf("<=") > 0)
{
int ndx = expr.IndexOf("<=");
string lstr = expr.Substring(0, ndx);
string rstr = expr.Substring(ndx + 2);
Evaluate(lstr);
double lval = result;
Evaluate(rstr);
double rval = result;
if(lval <= rval)
{
return true;
}
else
{
return false;
}
}
else if(expr.IndexOf(">=") > 0)
{
int ndx = expr.IndexOf(">=");
string lstr = expr.Substring(0, ndx);
string rstr = expr.Substring(ndx + 2);
Evaluate(lstr);
double lval = result;
Evaluate(rstr);
double rval = result;
if(lval >= rval)
{
return true;
}
else
{
return false;
}
}
else if(expr.IndexOf("!=") > 0)
{
int ndx = expr.IndexOf("!=");
string lstr = expr.Substring(0, ndx);
string rstr = expr.Substring(ndx + 2);
if(rstr.IndexOf("\"") > -1)
{
Variable var = m_oVarEngine.Find(lstr);
string strTrim = rstr.Trim();
string strSub = strTrim.Substring(1, strTrim.Length - 2);
if(var.StringValue.CompareTo(strSub) == 0)
{
return false;
}
else
{
return true;
}
}
else
{
Evaluate(lstr);
double lval = result;
Evaluate(rstr);
double rval = result;
if(lval != rval)
{
return true;
}
else
{
return false;
}
}
}
else if(expr.IndexOf("<") > 0)
{
int ndx = expr.IndexOf("<");
string lstr = expr.Substring(0, ndx);
string rstr = expr.Substring(ndx + 1);
Evaluate(lstr);
double lval = result;
Evaluate(rstr);
double rval = result;
if(lval < rval)
{
return true;
}
else
{
return false;
}
}
else if(expr.IndexOf(">") > 0)
{
int ndx = expr.IndexOf(">");
string lstr = expr.Substring(0, ndx);
string rstr = expr.Substring(ndx + 1);
Evaluate(lstr.Trim());
double lval = result;
Evaluate(rstr.Trim());
double rval = result;
<img src="http://
[Serializable]
public class RulesEngine: CollectionBase
{
Instance data membersInstance data members#region Instance data members
/**//**//**//// <summary>
/// Threading lock for Thread Safety. Allows multiple
/// readers at a time but only one writer at a time.
/// </summary>
static ReaderWriterLock m_oRWLock = new ReaderWriterLock();
/**//**//**//// <summary>
/// Timeout for ReaderWriterLock
/// </summary>
private int m_iTimeout = 1000;
/**//**//**//// <summary>
/// To be used in the future.
/// </summary>
private bool m_bUseInferencing = false;
/**//**//**//// <summary>
/// Inference object collection
/// </summary>
private InferenceCollection m_oInferences = new InferenceCollection();
/**//**//**//// <summary>
/// Variable engine for adding, getting and setting variables in this
/// Engine
/// </summary>
VariableEngine m_oVarEngine = new VariableEngine();
/**//**//**//// <summary>
/// Expression evaluation class to return values for expressions
/// </summary>
ExpressionMachine m_oExprMachine = new ExpressionMachine();
/**//**//**//// <summary>
/// Collection of Triggers
/// </summary>
TriggerCollection m_oTriggers = new TriggerCollection();
#endregion
PropertiesProperties#region Properties
/**//**//**//// <summary>
/// The property of the internal Variable Engine. (Set only)
/// </summary>
public VariableEngine VarEngine
{
set
{
this.m_oVarEngine = value;
}
}
public bool UseInferencing
{
get
{
return m_bUseInferencing;
}
set
{
m_bUseInferencing = value;
}
}
#endregion
Delegates and eventsDelegates and events#region Delegates and events
/**//**//**//// <summary>
/// Delegate for RuleEntered Event
/// </summary>
public delegate void RuleEnteredDelegate(RuleObject oRule);
/**//**//**//// <summary>
/// Event for RulEntered
/// </summary>
public event RuleEnteredDelegate RuleEntered;
/**//**//**//// <summary>
/// Delegate for RuleCompleted Event
/// </summary>
public delegate void RuleCompleteDelegate(RuleObject oRule);
/**//**//**//// <summary>
/// Event for RuleCompleted
/// </summary>
public event RuleCompleteDelegate RuleComplete;
/**//**//**//// <summary>
/// Delegate for VariableChanging
/// </summary>
public delegate void VariableChangingDelegate(Variable oVar);
/**//**//**//// <summary>
/// Event for VariableChanging
/// </summary>
public event VariableChangingDelegate VariableChanging;
/**//**//**//// <summary>
/// Delegate for VariableChanged
/// </summary>
public delegate void VariableChangedDelegate(Variable oOVar);
/**//**//**//// <summary>
/// Event for VariableChanged
/// </summary>
public event VariableChangedDelegate VariableChanged;
/**//**//**//// <summary>
/// Delegate for Adding a Variable to the Internal VariableEngine
/// </summary>
public delegate void VariableAddedDelegate(Variable oVar);
/**//**//**//// <summary>
/// Event for Adding a Variable to the Internal VariableEngine
/// </summary>
public event VariableAddedDelegate VariableAdded;
#endregion
CtorsCtors#region Ctors
/**//**//**//// <summary>
/// Default Constructor
/// </summary>
public RulesEngine()
{
}
#endregion
Trigger ManagementTrigger Management#region Trigger Management
/**//**//**//// <summary>
/// Adds a Trigger object to the internal Trigger collection
/// </summary>
/// <param name="oTrigger">the Trigger object to add</param>
public void AddTrigger(Trigger oTrigger)
{
m_oTriggers.Add(oTrigger);
}
/**//**//**//// <summary>
/// Adds a Trigger object tot he internal Trigger collection
/// </summary>
/// <param name="sTriggerId">the string id for this Trigger</param>
/// <param name="sVarID">the Variable ID to watch for</param>
/// <param name="sRuleID">the Rule ID to run if Trigger is Variable is changed</param>
public void AddTrigger(string sTriggerId, string sVarID, string sRuleID)
{
Trigger oTrigger = new Trigger(sTriggerId, sVarID, sRuleID);
m_oTriggers.Add(oTrigger);
}
#endregion
Variable managementVariable management#region Variable management
/**//**//**//// <summary>
/// Adds a Variable to the internal Variable Engine and publishs the VariableAdded event
/// </summary>
/// <param name="oVar">Variable object to add</param>
public void AddVariable(Variable oVar)
{
if(VariableAdded != null)
{
VariableAdded(oVar);
}
if(m_oVarEngine.Contains(oVar))
{
throw new DuplicateVariableException(oVar.ID);
}
else
{
m_oVarEngine.Add(oVar);
if (oVar is VariableDataset)
{
VariableDataset oVarDS = oVar as VariableDataset;
DataSet ds = oVar.ObjectValue as System.Data.DataSet;
}
}
}
/**//**//**//// <summary>
/// Gets the number of Variables in the Collection.
/// </summary>
/// <returns>int of the number of Variables</returns>
public int GetVariableCount()
{
return m_oVarEngine.Count;
}
/**//**//**//// <summary>
/// Gets a Variable by its ID.
/// </summary>
/// <param name="sID">String ID of Variable to find</param>
/// <returns>The Variable if found, and Null otherwise</returns>
public Variable GetVariable(string sID)
{
Variable oVar = m_oVarEngine[sID];
if(oVar == null)
{
throw new VariableNotFoundException(sID);
}
else
{
return oVar;
}
}
/**//**//**//// <summary>
/// Gets a Varaible by its Index
/// </summary>
/// <param name="iIndex">int Index</param>
/// <returns>The Variable is found and Null otherwise</returns>
public Variable GetVariable(int iIndex)
{
Variable oVar = m_oVarEngine[iIndex];
if(oVar == null)
{
throw new VariableNotFoundException(" at Index " + iIndex + " ");
}
else
{
return oVar;
}
}
/**//**//**//// <summary>
/// Sets the Variable whose ID is found to the value and publishs events for VariableChanging and VariableChanged.
/// </summary>
/// <remarks>
/// The Value object may be another Variable, a double, a bool, or a string.
/// </remarks>
/// <param name="sID">String ID of the Variable to find</param>
/// <param name="oValue">object Value to set the Variable to</param>
public void SetVariableValue(string sID, object oValue)
{
string sNewId = sID;
string sAttrID = "";
if(sID.IndexOf(".") > 0)
{
sNewId = sID.Substring(0, sID.IndexOf("."));
sAttrID = sID.Substring(sID.IndexOf(".") + 1);
}
Variable oVar = m_oVarEngine[sNewId];
if(oVar == null)
{
throw new VariableNotFoundException(sNewId);
}
if(oVar.VarType == Variable.VariableType.OBJECT)
{
if(oVar.HasA(sAttrID))
{
m_oVarEngine[sNewId].SetAttribute(sAttrID, oValue);
Variable oCheckVar = m_oVarEngine[sNewId];
if(VariableChanged != null && oCheckVar != null)
{
VariableChanged(m_oVarEngine[sNewId]);
}
CheckTrigger(sNewId);
}
}
else
{
if(VariableChanging != null && oVar != null)
{
VariableChanging(oVar);
}
string sOldID = m_oVarEngine[sNewId].ID;
m_oVarEngine[sID] = new Variable(sOldID, "" + oValue);
Variable oCheckVar = m_oVarEngine[sID];
if(VariableChanged != null && oCheckVar != null)
{
VariableChanged(m_oVarEngine[sNewId]);
}
CheckTrigger(sNewId);
}
}
/**//**//**//// <summary>
/// Sets the Variable found by the Index to the Value object
/// </summary>
/// <remarks>
/// The Value object may be another Variable, a double, a bool, or a string.
/// </remarks>
/// <param name="iIndex">int Index of the Variable</param>
/// <param name="oValue">The Value Object to set the Variable to</param>
public void SetVariableValue(int iIndex, object oValue)
{
if(m_oVarEngine[iIndex] == null)
{
throw new VariableNotFoundException(" at Index " + iIndex + " ");
}
else
{
string sOldID = m_oVarEngine[iIndex].ID;
Variable oVar = new Variable(sOldID, "" + oValue);
if(VariableChanging != null && oVar != null)
{
VariableChanging(oVar);
}
m_oVarEngine[iIndex] = oVar;
if(VariableChanged != null && oVar != null)
{
VariableChanged(m_oVarEngine[sOldID]);
}
CheckTrigger(sOldID);
}
}
/**//**//**//// <summary>
/// Determines if the Variable exists in the internal VariableEngine.
/// </summary>
/// <param name="oVar">Variable to check the existence of</param>
/// <returns>True if found, and false otherwise</returns>
public bool VariableExists(Variable oVar)
{
return m_oVarEngine.Contains(oVar);
}
#endregion
Run RulesRun Rules#region Run Rules
/**//**//**//// <summary>
/// "Runs" and RuleObject indentified by the ID supplied.
/// </summary>
/// <remarks>
/// This method finds the RuleObject by its ID then calls the RunRule(RuleObject oRule) method.
/// If the RuleObject is not found then nothing is done.
/// </remarks>
/// <param name="sID">String ID of the RuleObject to Run</param>
public void RunRule(string sID)
{
RuleObject oRule = GetRule(null, sID);
if(oRule != null)
{
RunRule(oRule);
}
}
/**//**//**//// <summary>
/// Runs Rule by RuleID and returning the Variable with ID
/// </summary>
/// <param name="sRuleID">string of RuleID to run</param>
/// <param name="sVarID">string of Variable to return</param>
/// <returns>Variable identifed by ID</returns>
public Variable RunRule(string sRuleID, string sVarID)
{
RuleObject oRule = GetRule(null, sRuleID);
if(oRule != null)
{
RunRule(oRule);
}
return m_oVarEngine[sVarID];
}
/**//**//**//// <summary>
/// Returns Rule from ID
/// </summary>
/// <remarks>
/// String id can be a dot operated string to identify sub rules.
/// This method will recurse the string until the sub-rule is found.
/// </remarks>
/// <param name="oParent">Parent Rule to search form</param>
/// <param name="sRuleID">ID of rule to find</param>
/// <returns>Rule object or RuleNotFoundException</returns>
public RuleObject GetRule(RuleObject oParent, string sRuleID)
{
int iSubIndex = sRuleID.IndexOf(".");
if(oParent == null)
{
if(iSubIndex > 0)
{
string sRuleStr = sRuleID.Substring(0, iSubIndex);
string sSubStr = sRuleID.Substring(iSubIndex + 1);
RuleObject oParentRule = Find(sRuleStr);
if(oParentRule != null)
{
return GetRule(oParentRule, sSubStr);
}
else
{
throw new RuleNotFoundException(sRuleStr);
}
}
else
{
RuleObject oRule = Find(sRuleID);
if(oRule == null)
{
throw new RuleNotFoundException(sRuleID);
}
else
{
return oRule;
}
}
}
else
{
if(iSubIndex > 0)
{
string sRuleStr = sRuleID.Substring(0, iSubIndex);
string sSubStr = sRuleID.Substring(iSubIndex + 1);
RuleObject oParentRule = Find(sRuleStr);
if(oParentRule != null)
{
return GetRule(oParentRule, sSubStr);
}
else
{
throw new RuleNotFoundException(sRuleStr);
}
}
else
{
RuleObject oRule = oParent.GetSubRule(sRuleID);
if(oRule == null)
{
throw new RuleNotFoundException(sRuleID);
}
else
{
return oRule;
}
}
}
}
/**//**//**//// <summary>
/// "Runs" the RuleObject and Checks the Actions for a match. Then "Runs" the SubRule list.
/// </summary>
/// <remarks>
/// </remarks>
/// <param name="oRule"></param>
private void RunRule(RuleObject oRule)
{
if(oRule != null)
{
if(RuleEntered != null)
{
RuleEntered(oRule);
}
bool bNoExpression = true;
if(oRule.HasExpression)
{
bNoExpression = false;
m_oExprMachine.Resolve(oRule.Expression, m_oVarEngine);
}
else
{
bNoExpression = true;
}
int iCnt = oRule.GetActionCount();
string sMatchValue = m_oExprMachine.StringResult;
for(int i = 0; i < iCnt; i++)
{
Action oAction = oRule[i];
m_oExprMachine.Resolve(oAction.TargetVariable.StringValue, m_oVarEngine);
if(m_oExprMachine.StringResult.CompareTo(sMatchValue) == 0 || bNoExpression)
{
if(oRule[i].TypeAction == Action.ActionType.Stop)
{
break;
}
else if(oRule[i].TypeAction == Action.ActionType.MakeVar)
{
if(oAction.AssignVariable.VarType == Variable.VariableType.OBJECT)
{
Variable oNewVar = new Variable(oAction.ID, (IVariableObject) oAction.AssignVariable.ObjectValue);
if(VariableAdded != null)
{
VariableAdded(oNewVar);
}
m_oVarEngine.Add(oNewVar);
}
else
{
this.m_oExprMachine.Resolve(oAction.AssignVariable.StringValue, m_oVarEngine);
Variable oNewVar = new Variable(oAction.ID, m_oExprMachine.StringResult);
if(VariableAdded != null)
{
VariableAdded(oNewVar);
}
m_oVarEngine.Add(oNewVar);
}
}
else if(oRule[i].TypeAction == Action.ActionType.Var)
{
string sID = oRule[i].ID;
string sNewId = sID;
if(sID.IndexOf(".") > 0)
{
sNewId = sID.Substring(0, sID.IndexOf("."));
}
Variable oVar = m_oVarEngine[sNewId];
if(oVar != null)
{
this.m_oExprMachine.Resolve(oAction.AssignVariable.StringValue, m_oVarEngine);
this.SetVariableValue(oRule[i].ID, m_oExprMachine.StringResult);
}
else
{
Variable oNewVar = new Variable(oAction.ID,oAction.AssignVariable.StringValue);
if(VariableAdded != null)
{
VariableAdded(oNewVar);
}
m_oVarEngine.Add(oNewVar);
}
}
else if(oRule[i].TypeAction == Action.ActionType.Run)
{
RunRule(oRule[i].ID);
}
}
}
if(oRule.HasSubRules)
{
for(int s = 0; s < oRule.GetSubRuleCount(); s++)
{
RuleObject oSubRule = oRule.GetSubRule(s);
RunRule(oSubRule);
}
}
if(RuleComplete != null)
{
RuleComplete(oRule);
}
}
}
#endregion
Inference MethodsInference Methods#region Inference Methods
/**//**//**//// <summary>
/// Examines the Rule and adds inferencing using the Variable Ids in the Rule
/// </summary>
/// <param name="oRule"></param>
private void AddInference(RuleObject oRule)
{
if(oRule.UseInferencing)
{
string [] sExprs = GetVarIDs(oRule.Expression);
for( int iExp = 0 ; iExp < sExprs.Length; iExp++)
{
AddInference(sExprs[iExp], oRule.GetPathID());
}
for(int a = 0; a < oRule.GetActionCount(); a++)
{
Action oAction = oRule[a];
string [] sAIds = GetVarIDs(oAction.AssignString);
for(int ac = 0; ac < sAIds.Length; ac++)
{
AddInference(sAIds[ac], oRule.GetPathID());
}
string [] sTIds = GetVarIDs(oAction.TargetString);
for(int at = 0; at < sTIds.Length; at++)
{
AddInference(sTIds[at], oRule.GetPathID());
}
}
for(int s = 0; s < oRule.GetSubRuleCount(); s++)
{
RuleObject oSubRule = oRule.GetSubRule(s);
AddInference(oSubRule);
}
}
}
/**//**//**//// <summary>
/// Adds an Inference by VariableID and RulePath
/// </summary>
/// <param name="sVarID"></param>
/// <param name="sPathID"></param>
private void AddInference(string sVarID, string sPathID)
{
if(this.m_oInferences.Find(sVarID) != null)
{
Inference oInference = m_oInferences.Find(sVarID);
oInference.AddRuleID(sPathID);
}
else
{
Inference oInference = new Inference();
oInference.VariableID = sVarID;
oInference.AddRuleID(sPathID);
m_oInferences.Add(oInference);
}
}
/**//**//**//// <summary>
/// Gets an array of VariableIDs from and expression. This method is used
/// to Add inferencing by Rule reference.
/// </summary>
/// <param name="sExpr">Expression from rule</param>
/// <returns>Array of VariableIds</returns>
private string[] GetVarIDs(string sExpr)
{
ArrayList oVarIds = new ArrayList();
char [] space = {' '};
string [] sStrs = sExpr.Split(space);
for(int i = 0; i < sStrs.Length; i++)
{
if(m_oVarEngine.FindIndexOf(sStrs[i]) >= 0)
{
oVarIds.Add(sStrs[i]);
}
}
return (string[]) oVarIds.ToArray(typeof(string));
}
/**//**//**//// <summary>
/// Runs all rules affected by a change of the Variable.
/// </summary>
/// <param name="sVarID"></param>
public void RunInferencing(string sVarID)
{
if(this.m_oInferences.Find(sVarID) != null)
{
Inference oInference = m_oInferences.Find(sVarID);
for(int r = 0; r < oInference.GetRuleCount(); r++)
{
string sRuleID = oInference.GetRuleID(r);
RunRule(sRuleID);
}
}
}
#endregion
Expression EvaluationExpression Evaluation#region Expression Evaluation
/**//**//**//// <summary>
/// Runs and Expression and if it is true returns the true Variable and if False returns the false Variable
/// </summary>
/// <param name="expr">string expression to evaluate</param>
/// <param name="sTrueVarID">True Variable ID</param>
/// <param name="sFalseVarID">False Variable ID</param>
/// <returns></returns>
public Variable RunExpression(string expr, string sTrueVarID, string sFalseVarID)
{
this.m_oExprMachine.Resolve(expr, m_oVarEngine);
if(m_oExprMachine.BoolResult)
{
return this.m_oVarEngine[sTrueVarID];
}
else
{
return this.m_oVarEngine[sFalseVarID];
}
}
/**//**//**//// <summary>
/// Evaluates the Expression and returns the result in a Variable.
/// </summary>
/// <param name="expr">Expression to evaluate</param>
/// <returns>a Variable containing the result of the expression</returns>
public Variable RunExpression(string expr)
{
this.m_oExprMachine.Resolve(expr, m_oVarEngine);
Variable oRetVar = new Variable();
oRetVar.StringValue = m_oExprMachine.StringResult;
return oRetVar;
}
#endregion
Trigger methodsTrigger methods#region Trigger methods
/**//**//**//// <summary>
/// Gets trigger at index
/// </summary>
/// <param name="i">index</param>
/// <returns>Trigger object at index</returns>
public Trigger GetTrigger(int i)
{
return m_oTriggers[i];
}
/**//**//**//// <summary>
/// Get Trigger by ID
/// </summary>
/// <param name="sTriggerID">Id of Trigger</param>
/// <returns>Trigger by ID</returns>
public Trigger GetTrigger(string sTriggerID)
{
return m_oTriggers[sTriggerID];
}
/**//**//**//// <summary>
/// Gets the number of Triggers
/// </summary>
/// <returns>count of triggers</returns>
public int GetTriggerCount()
{
return m_oTriggers.Count;
}
/**//**//**//// <summary>
/// Runs the Rule associated with the Variable Id
/// </summary>
/// <param name="sVarID"></param>
private void CheckTrigger(string sVarID)
{
Trigger oTrigger = m_oTriggers[sVarID];
if(oTrigger != null)
{
RunRule(oTrigger.RuleID);
}
}
#endregion
List managementList management#region List management
/**//**//**//// <summary>
/// Adds a RuleObject to the RulesEngine
/// </summary>
/// <remarks>
/// If the RuleObject already Exists the RuleObject will be overwritten.
/// </remarks>
/// <param name="oRule">The RuleObject to Add</param>
public void Add(RuleObject oRule)
{
m_oRWLock.AcquireWriterLock(m_iTimeout);
try
{
int iFindIndexOf = FindIndexOf(oRule.ID);
// RuleObject with ID is not found now find where it belongs and insert it.
if(iFindIndexOf < 0)
{
RuleObject oProbe = new RuleObject();
int high = List.Count, low = -1, probe;
while (high - low > 1)
{
probe = (high + low) / 2;
oProbe = (RuleObject) List[probe];
if (oProbe.CompareTo(oRule.ID) < 0)
low = probe;
else
high = probe;
}
if(low < 0)
{
low = 0;
}
List.Insert(high, oRule);
this.AddInference(oRule);
}
else
{
//List[iFindIndexOf] = oRule;
throw new DuplicateRuleIDException(oRule.ID);
}
}
finally
{
m_oRWLock.ReleaseWriterLock();
}
}
/**//**//**//// <summary>
/// Adds and Array of RuleObjects to the RulesEngine.
/// </summary>
/// <remarks>
/// Only RuleObject in the ArrayList will be added.
/// </remarks>
/// <param name="oArrayList">ArrayList to add from</param>
public void AddAll(ArrayList oArrayList)
{
m_oRWLock.AcquireWriterLock(m_iTimeout);
try
{
foreach(RuleObject ruleObj in oArrayList)
{
Add(ruleObj);
}
}
finally
{
m_oRWLock.ReleaseWriterLock();
}
}
/**//**//**//// <summary>
/// Inserts a RuleObject at the Index
/// </summary>
/// <param name="index">int Index</param>
/// <param name="oRule">RuleObject to insert</param>
public void Insert(int index, RuleObject oRule)
{
m_oRWLock.AcquireWriterLock(m_iTimeout);
try
{
List.Insert(index, oRule);
}
finally
{
m_oRWLock.ReleaseWriterLock();
}
}
/**//**//**//// <summary>
/// Removes RuleObject
/// </summary>
/// <param name="oRule">RuleObject to remove</param>
public void Remove(RuleObject oRule)
{
m_oRWLock.AcquireWriterLock(m_iTimeout);
try
{
List.Remove(oRule);
}
finally
{
m_oRWLock.ReleaseWriterLock();
}
}
/**//**//**//// <summary>
/// Determines if a RuleObject exists
/// </summary>
/// <param name="oRule">RuleObject to check for</param>
/// <returns>True if found and False otherwise</returns>
public bool Contains(RuleObject oRule)
{
m_oRWLock.AcquireReaderLock(m_iTimeout);
try
{
return List.Contains(oRule);
}
finally
{
m_oRWLock.ReleaseReaderLock();
}
}
/**//**//**//// <summary>
/// Gets the Index of a RuleObject
/// </summary>
/// <param name="oRule">The RuleObject to get the Index of</param>
/// <returns>the index of the RuleObject</returns>
public int IndexOf(RuleObject oRule)
{
m_oRWLock.AcquireReaderLock(m_iTimeout);
try
{
return List.IndexOf(oRule);
}
finally
{
m_oRWLock.ReleaseReaderLock();
}
}
/**//**//**//// <summary>
/// Copies the Array to the RuleObject List
/// </summary>
/// <param name="array">The Variable Array to copy</param>
/// <param name="index">The starting index.</param>
public void CopyTo(Variable[] array, int index)
{
m_oRWLock.AcquireWriterLock(m_iTimeout);
try
{
List.CopyTo(array, index);
}
finally
{
m_oRWLock.ReleaseWriterLock();
}
}
/**//**//**//// <summary>
/// Re-Sorts Rule Collection
/// </summary>
public void ReSort()
{
ArrayList arr = new ArrayList(List);
List.Clear();
this.AddAll(arr);
}
#endregion
IndexerIndexer#region Indexer
/**//**//**//// <summary>
/// Indexer of RuleObject by int Index
/// </summary>
public RuleObject this[int index]
{
get
{
m_oRWLock.AcquireReaderLock(m_iTimeout);
try
{
return (RuleObject)List[index];
}
finally
{
m_oRWLock.ReleaseReaderLock();
}
}
set
{
m_oRWLock.AcquireWriterLock(m_iTimeout);
try
{
List[index] = value;
}
finally
{
m_oRWLock.ReleaseWriterLock();
}
}
}
/**//**//**//// <summary>
/// Indexer of RuleObject by String ID
/// </summary>
public RuleObject this[string sID]
{
get
{
return Find(sID);
}
set
{
int iFound = FindIndexOf(sID);
if(iFound >= 0)
{
List[iFound] = value;
}
}
}
#endregion
Find and SortFind and Sort#region Find and Sort
/**//**//**//// <summary>
/// Finds the RuleObject by its ID
/// </summary>
/// <param name="strTarget">The ID of the RuleObject to find</param>
/// <returns>The RuleObject if found and Null otherwise</returns>
public RuleObject Find(string strTarget)
{
m_oRWLock.AcquireReaderLock(m_iTimeout);
try
{
if(List.Count <= 0)
{
throw new RuleNotFoundException(strTarget);
}
else if(List.Count == 1)
{
return (RuleObject) List[0];
}
RuleObject oRetVar = new RuleObject();
RuleObject oProbe = new RuleObject();
int high = List.Count, low = -1, probe;
while (high - low > 1)
{
probe = (high + low) / 2;
oProbe = (RuleObject) List[probe];
if (oProbe.CompareTo(strTarget) < 0)
low = probe;
else
high = probe;
}
if(high == List.Count)
{
throw new RuleNotFoundException(strTarget);
}
else
{
oRetVar = (RuleObject) List[high];
if(oRetVar.CompareTo(strTarget) == 0)
{
return oRetVar;
}
else if(oRetVar.CompareTo(strTarget) < 0)
{
throw new RuleNotFoundException(strTarget);;
}
else
{
throw new RuleNotFoundException(strTarget);
}
}
}
finally
{
m_oRWLock.ReleaseReaderLock();
}
}
/**//**//**//// <summary>
/// Return the Index of a RuleObject whose ID matches the string Target
/// </summary>
/// <param name="strTarget">The string ID of the RuleObject to find</param>
/// <returns>the int index of the RuleObject if it is found and -1 if it is not found.</returns>
public int FindIndexOf(string strTarget)
{
m_oRWLock.AcquireReaderLock(m_iTimeout);
try
{
if(List.Count <= 0)
{
return -1;
}
RuleObject oRetVar = new RuleObject();
RuleObject oProbe = new RuleObject();
int high = List.Count, low = -1, probe;
while (high - low > 1)
{
probe = (high + low) / 2;
oProbe = (RuleObject) List[probe];
if (oProbe.CompareTo(strTarget) < 0)
low = probe;
else
high = probe;
}
if(low < 0)
{
low = 0;
}
if (high == List.Count)
{
return -1;
}
else
{
oRetVar = (RuleObject) List[high];
if(oRetVar.CompareTo(strTarget) > 0)
{
return -1;
}
else if(oRetVar.CompareTo(strTarget) == 0)
{
return high;
}
else
{
return low;
}
}
}
finally
{
m_oRWLock.ReleaseReaderLock();
}
}
#endregion
}
}
在其中Trigger Management,Variable management用来获取相应的触发器和变量,而所有的RUNRULE方法最后都落实到了 private void RunRule(RuleObject oRule)这个方法上来,该方法被调用时应该已经确认了触发器,变量等RULE的组成部分都没有逻辑上的错误,这个方法首先会把RULE中含有表达式的成分进行解析,然后再循环对所有的ACTION进行遍历,按照ACTION的类型作出相应的处理,如果这个ACTION是一个驱动RULE运行的话我们就必须要知道对应的RULE ID来调用,如果是嵌套的情况还要递归调用RUNRULE方法,一个运行时中在引擎内部只有ID是被唯一识别的,管理好几大重要类型的ID体系是很重要的,这种管理包括新增,识别,判重,修改和删除。在这种需求的前提下LIST比堆栈更灵活可靠。当然,为了判断该RULE已经完成作业,引擎会给出一个事件public event RuleCompleteDelegate RuleComplete;并在完成的时候调用它,这样,我们就可以在实际程序中重写这个事件,来满足日志,跳转,状态转换等UI需求。
public class RulesEngine: CollectionBase
{
Instance data membersInstance data members#region Instance data members
/**//**//**//// <summary>
/// Threading lock for Thread Safety. Allows multiple
/// readers at a time but only one writer at a time.
/// </summary>
static ReaderWriterLock m_oRWLock = new ReaderWriterLock();
/**//**//**//// <summary>
/// Timeout for ReaderWriterLock
/// </summary>
private int m_iTimeout = 1000;
/**//**//**//// <summary>
/// To be used in the future.
/// </summary>
private bool m_bUseInferencing = false;
/**//**//**//// <summary>
/// Inference object collection
/// </summary>
private InferenceCollection m_oInferences = new InferenceCollection();
/**//**//**//// <summary>
/// Variable engine for adding, getting and setting variables in this
/// Engine
/// </summary>
VariableEngine m_oVarEngine = new VariableEngine();
/**//**//**//// <summary>
/// Expression evaluation class to return values for expressions
/// </summary>
ExpressionMachine m_oExprMachine = new ExpressionMachine();
/**//**//**//// <summary>
/// Collection of Triggers
/// </summary>
TriggerCollection m_oTriggers = new TriggerCollection();
#endregion
PropertiesProperties#region Properties
/**//**//**//// <summary>
/// The property of the internal Variable Engine. (Set only)
/// </summary>
public VariableEngine VarEngine
{
set
{
this.m_oVarEngine = value;
}
}
public bool UseInferencing
{
get
{
return m_bUseInferencing;
}
set
{
m_bUseInferencing = value;
}
}
#endregion
Delegates and eventsDelegates and events#region Delegates and events
/**//**//**//// <summary>
/// Delegate for RuleEntered Event
/// </summary>
public delegate void RuleEnteredDelegate(RuleObject oRule);
/**//**//**//// <summary>
/// Event for RulEntered
/// </summary>
public event RuleEnteredDelegate RuleEntered;
/**//**//**//// <summary>
/// Delegate for RuleCompleted Event
/// </summary>
public delegate void RuleCompleteDelegate(RuleObject oRule);
/**//**//**//// <summary>
/// Event for RuleCompleted
/// </summary>
public event RuleCompleteDelegate RuleComplete;
/**//**//**//// <summary>
/// Delegate for VariableChanging
/// </summary>
public delegate void VariableChangingDelegate(Variable oVar);
/**//**//**//// <summary>
/// Event for VariableChanging
/// </summary>
public event VariableChangingDelegate VariableChanging;
/**//**//**//// <summary>
/// Delegate for VariableChanged
/// </summary>
public delegate void VariableChangedDelegate(Variable oOVar);
/**//**//**//// <summary>
/// Event for VariableChanged
/// </summary>
public event VariableChangedDelegate VariableChanged;
/**//**//**//// <summary>
/// Delegate for Adding a Variable to the Internal VariableEngine
/// </summary>
public delegate void VariableAddedDelegate(Variable oVar);
/**//**//**//// <summary>
/// Event for Adding a Variable to the Internal VariableEngine
/// </summary>
public event VariableAddedDelegate VariableAdded;
#endregion
CtorsCtors#region Ctors
/**//**//**//// <summary>
/// Default Constructor
/// </summary>
public RulesEngine()
{
}
#endregion
Trigger ManagementTrigger Management#region Trigger Management
/**//**//**//// <summary>
/// Adds a Trigger object to the internal Trigger collection
/// </summary>
/// <param name="oTrigger">the Trigger object to add</param>
public void AddTrigger(Trigger oTrigger)
{
m_oTriggers.Add(oTrigger);
}
/**//**//**//// <summary>
/// Adds a Trigger object tot he internal Trigger collection
/// </summary>
/// <param name="sTriggerId">the string id for this Trigger</param>
/// <param name="sVarID">the Variable ID to watch for</param>
/// <param name="sRuleID">the Rule ID to run if Trigger is Variable is changed</param>
public void AddTrigger(string sTriggerId, string sVarID, string sRuleID)
{
Trigger oTrigger = new Trigger(sTriggerId, sVarID, sRuleID);
m_oTriggers.Add(oTrigger);
}
#endregion
Variable managementVariable management#region Variable management
/**//**//**//// <summary>
/// Adds a Variable to the internal Variable Engine and publishs the VariableAdded event
/// </summary>
/// <param name="oVar">Variable object to add</param>
public void AddVariable(Variable oVar)
{
if(VariableAdded != null)
{
VariableAdded(oVar);
}
if(m_oVarEngine.Contains(oVar))
{
throw new DuplicateVariableException(oVar.ID);
}
else
{
m_oVarEngine.Add(oVar);
if (oVar is VariableDataset)
{
VariableDataset oVarDS = oVar as VariableDataset;
DataSet ds = oVar.ObjectValue as System.Data.DataSet;
}
}
}
/**//**//**//// <summary>
/// Gets the number of Variables in the Collection.
/// </summary>
/// <returns>int of the number of Variables</returns>
public int GetVariableCount()
{
return m_oVarEngine.Count;
}
/**//**//**//// <summary>
/// Gets a Variable by its ID.
/// </summary>
/// <param name="sID">String ID of Variable to find</param>
/// <returns>The Variable if found, and Null otherwise</returns>
public Variable GetVariable(string sID)
{
Variable oVar = m_oVarEngine[sID];
if(oVar == null)
{
throw new VariableNotFoundException(sID);
}
else
{
return oVar;
}
}
/**//**//**//// <summary>
/// Gets a Varaible by its Index
/// </summary>
/// <param name="iIndex">int Index</param>
/// <returns>The Variable is found and Null otherwise</returns>
public Variable GetVariable(int iIndex)
{
Variable oVar = m_oVarEngine[iIndex];
if(oVar == null)
{
throw new VariableNotFoundException(" at Index " + iIndex + " ");
}
else
{
return oVar;
}
}
/**//**//**//// <summary>
/// Sets the Variable whose ID is found to the value and publishs events for VariableChanging and VariableChanged.
/// </summary>
/// <remarks>
/// The Value object may be another Variable, a double, a bool, or a string.
/// </remarks>
/// <param name="sID">String ID of the Variable to find</param>
/// <param name="oValue">object Value to set the Variable to</param>
public void SetVariableValue(string sID, object oValue)
{
string sNewId = sID;
string sAttrID = "";
if(sID.IndexOf(".") > 0)
{
sNewId = sID.Substring(0, sID.IndexOf("."));
sAttrID = sID.Substring(sID.IndexOf(".") + 1);
}
Variable oVar = m_oVarEngine[sNewId];
if(oVar == null)
{
throw new VariableNotFoundException(sNewId);
}
if(oVar.VarType == Variable.VariableType.OBJECT)
{
if(oVar.HasA(sAttrID))
{
m_oVarEngine[sNewId].SetAttribute(sAttrID, oValue);
Variable oCheckVar = m_oVarEngine[sNewId];
if(VariableChanged != null && oCheckVar != null)
{
VariableChanged(m_oVarEngine[sNewId]);
}
CheckTrigger(sNewId);
}
}
else
{
if(VariableChanging != null && oVar != null)
{
VariableChanging(oVar);
}
string sOldID = m_oVarEngine[sNewId].ID;
m_oVarEngine[sID] = new Variable(sOldID, "" + oValue);
Variable oCheckVar = m_oVarEngine[sID];
if(VariableChanged != null && oCheckVar != null)
{
VariableChanged(m_oVarEngine[sNewId]);
}
CheckTrigger(sNewId);
}
}
/**//**//**//// <summary>
/// Sets the Variable found by the Index to the Value object
/// </summary>
/// <remarks>
/// The Value object may be another Variable, a double, a bool, or a string.
/// </remarks>
/// <param name="iIndex">int Index of the Variable</param>
/// <param name="oValue">The Value Object to set the Variable to</param>
public void SetVariableValue(int iIndex, object oValue)
{
if(m_oVarEngine[iIndex] == null)
{
throw new VariableNotFoundException(" at Index " + iIndex + " ");
}
else
{
string sOldID = m_oVarEngine[iIndex].ID;
Variable oVar = new Variable(sOldID, "" + oValue);
if(VariableChanging != null && oVar != null)
{
VariableChanging(oVar);
}
m_oVarEngine[iIndex] = oVar;
if(VariableChanged != null && oVar != null)
{
VariableChanged(m_oVarEngine[sOldID]);
}
CheckTrigger(sOldID);
}
}
/**//**//**//// <summary>
/// Determines if the Variable exists in the internal VariableEngine.
/// </summary>
/// <param name="oVar">Variable to check the existence of</param>
/// <returns>True if found, and false otherwise</returns>
public bool VariableExists(Variable oVar)
{
return m_oVarEngine.Contains(oVar);
}
#endregion
Run RulesRun Rules#region Run Rules
/**//**//**//// <summary>
/// "Runs" and RuleObject indentified by the ID supplied.
/// </summary>
/// <remarks>
/// This method finds the RuleObject by its ID then calls the RunRule(RuleObject oRule) method.
/// If the RuleObject is not found then nothing is done.
/// </remarks>
/// <param name="sID">String ID of the RuleObject to Run</param>
public void RunRule(string sID)
{
RuleObject oRule = GetRule(null, sID);
if(oRule != null)
{
RunRule(oRule);
}
}
/**//**//**//// <summary>
/// Runs Rule by RuleID and returning the Variable with ID
/// </summary>
/// <param name="sRuleID">string of RuleID to run</param>
/// <param name="sVarID">string of Variable to return</param>
/// <returns>Variable identifed by ID</returns>
public Variable RunRule(string sRuleID, string sVarID)
{
RuleObject oRule = GetRule(null, sRuleID);
if(oRule != null)
{
RunRule(oRule);
}
return m_oVarEngine[sVarID];
}
/**//**//**//// <summary>
/// Returns Rule from ID
/// </summary>
/// <remarks>
/// String id can be a dot operated string to identify sub rules.
/// This method will recurse the string until the sub-rule is found.
/// </remarks>
/// <param name="oParent">Parent Rule to search form</param>
/// <param name="sRuleID">ID of rule to find</param>
/// <returns>Rule object or RuleNotFoundException</returns>
public RuleObject GetRule(RuleObject oParent, string sRuleID)
{
int iSubIndex = sRuleID.IndexOf(".");
if(oParent == null)
{
if(iSubIndex > 0)
{
string sRuleStr = sRuleID.Substring(0, iSubIndex);
string sSubStr = sRuleID.Substring(iSubIndex + 1);
RuleObject oParentRule = Find(sRuleStr);
if(oParentRule != null)
{
return GetRule(oParentRule, sSubStr);
}
else
{
throw new RuleNotFoundException(sRuleStr);
}
}
else
{
RuleObject oRule = Find(sRuleID);
if(oRule == null)
{
throw new RuleNotFoundException(sRuleID);
}
else
{
return oRule;
}
}
}
else
{
if(iSubIndex > 0)
{
string sRuleStr = sRuleID.Substring(0, iSubIndex);
string sSubStr = sRuleID.Substring(iSubIndex + 1);
RuleObject oParentRule = Find(sRuleStr);
if(oParentRule != null)
{
return GetRule(oParentRule, sSubStr);
}
else
{
throw new RuleNotFoundException(sRuleStr);
}
}
else
{
RuleObject oRule = oParent.GetSubRule(sRuleID);
if(oRule == null)
{
throw new RuleNotFoundException(sRuleID);
}
else
{
return oRule;
}
}
}
}
/**//**//**//// <summary>
/// "Runs" the RuleObject and Checks the Actions for a match. Then "Runs" the SubRule list.
/// </summary>
/// <remarks>
/// </remarks>
/// <param name="oRule"></param>
private void RunRule(RuleObject oRule)
{
if(oRule != null)
{
if(RuleEntered != null)
{
RuleEntered(oRule);
}
bool bNoExpression = true;
if(oRule.HasExpression)
{
bNoExpression = false;
m_oExprMachine.Resolve(oRule.Expression, m_oVarEngine);
}
else
{
bNoExpression = true;
}
int iCnt = oRule.GetActionCount();
string sMatchValue = m_oExprMachine.StringResult;
for(int i = 0; i < iCnt; i++)
{
Action oAction = oRule[i];
m_oExprMachine.Resolve(oAction.TargetVariable.StringValue, m_oVarEngine);
if(m_oExprMachine.StringResult.CompareTo(sMatchValue) == 0 || bNoExpression)
{
if(oRule[i].TypeAction == Action.ActionType.Stop)
{
break;
}
else if(oRule[i].TypeAction == Action.ActionType.MakeVar)
{
if(oAction.AssignVariable.VarType == Variable.VariableType.OBJECT)
{
Variable oNewVar = new Variable(oAction.ID, (IVariableObject) oAction.AssignVariable.ObjectValue);
if(VariableAdded != null)
{
VariableAdded(oNewVar);
}
m_oVarEngine.Add(oNewVar);
}
else
{
this.m_oExprMachine.Resolve(oAction.AssignVariable.StringValue, m_oVarEngine);
Variable oNewVar = new Variable(oAction.ID, m_oExprMachine.StringResult);
if(VariableAdded != null)
{
VariableAdded(oNewVar);
}
m_oVarEngine.Add(oNewVar);
}
}
else if(oRule[i].TypeAction == Action.ActionType.Var)
{
string sID = oRule[i].ID;
string sNewId = sID;
if(sID.IndexOf(".") > 0)
{
sNewId = sID.Substring(0, sID.IndexOf("."));
}
Variable oVar = m_oVarEngine[sNewId];
if(oVar != null)
{
this.m_oExprMachine.Resolve(oAction.AssignVariable.StringValue, m_oVarEngine);
this.SetVariableValue(oRule[i].ID, m_oExprMachine.StringResult);
}
else
{
Variable oNewVar = new Variable(oAction.ID,oAction.AssignVariable.StringValue);
if(VariableAdded != null)
{
VariableAdded(oNewVar);
}
m_oVarEngine.Add(oNewVar);
}
}
else if(oRule[i].TypeAction == Action.ActionType.Run)
{
RunRule(oRule[i].ID);
}
}
}
if(oRule.HasSubRules)
{
for(int s = 0; s < oRule.GetSubRuleCount(); s++)
{
RuleObject oSubRule = oRule.GetSubRule(s);
RunRule(oSubRule);
}
}
if(RuleComplete != null)
{
RuleComplete(oRule);
}
}
}
#endregion
Inference MethodsInference Methods#region Inference Methods
/**//**//**//// <summary>
/// Examines the Rule and adds inferencing using the Variable Ids in the Rule
/// </summary>
/// <param name="oRule"></param>
private void AddInference(RuleObject oRule)
{
if(oRule.UseInferencing)
{
string [] sExprs = GetVarIDs(oRule.Expression);
for( int iExp = 0 ; iExp < sExprs.Length; iExp++)
{
AddInference(sExprs[iExp], oRule.GetPathID());
}
for(int a = 0; a < oRule.GetActionCount(); a++)
{
Action oAction = oRule[a];
string [] sAIds = GetVarIDs(oAction.AssignString);
for(int ac = 0; ac < sAIds.Length; ac++)
{
AddInference(sAIds[ac], oRule.GetPathID());
}
string [] sTIds = GetVarIDs(oAction.TargetString);
for(int at = 0; at < sTIds.Length; at++)
{
AddInference(sTIds[at], oRule.GetPathID());
}
}
for(int s = 0; s < oRule.GetSubRuleCount(); s++)
{
RuleObject oSubRule = oRule.GetSubRule(s);
AddInference(oSubRule);
}
}
}
/**//**//**//// <summary>
/// Adds an Inference by VariableID and RulePath
/// </summary>
/// <param name="sVarID"></param>
/// <param name="sPathID"></param>
private void AddInference(string sVarID, string sPathID)
{
if(this.m_oInferences.Find(sVarID) != null)
{
Inference oInference = m_oInferences.Find(sVarID);
oInference.AddRuleID(sPathID);
}
else
{
Inference oInference = new Inference();
oInference.VariableID = sVarID;
oInference.AddRuleID(sPathID);
m_oInferences.Add(oInference);
}
}
/**//**//**//// <summary>
/// Gets an array of VariableIDs from and expression. This method is used
/// to Add inferencing by Rule reference.
/// </summary>
/// <param name="sExpr">Expression from rule</param>
/// <returns>Array of VariableIds</returns>
private string[] GetVarIDs(string sExpr)
{
ArrayList oVarIds = new ArrayList();
char [] space = {' '};
string [] sStrs = sExpr.Split(space);
for(int i = 0; i < sStrs.Length; i++)
{
if(m_oVarEngine.FindIndexOf(sStrs[i]) >= 0)
{
oVarIds.Add(sStrs[i]);
}
}
return (string[]) oVarIds.ToArray(typeof(string));
}
/**//**//**//// <summary>
/// Runs all rules affected by a change of the Variable.
/// </summary>
/// <param name="sVarID"></param>
public void RunInferencing(string sVarID)
{
if(this.m_oInferences.Find(sVarID) != null)
{
Inference oInference = m_oInferences.Find(sVarID);
for(int r = 0; r < oInference.GetRuleCount(); r++)
{
string sRuleID = oInference.GetRuleID(r);
RunRule(sRuleID);
}
}
}
#endregion
Expression EvaluationExpression Evaluation#region Expression Evaluation
/**//**//**//// <summary>
/// Runs and Expression and if it is true returns the true Variable and if False returns the false Variable
/// </summary>
/// <param name="expr">string expression to evaluate</param>
/// <param name="sTrueVarID">True Variable ID</param>
/// <param name="sFalseVarID">False Variable ID</param>
/// <returns></returns>
public Variable RunExpression(string expr, string sTrueVarID, string sFalseVarID)
{
this.m_oExprMachine.Resolve(expr, m_oVarEngine);
if(m_oExprMachine.BoolResult)
{
return this.m_oVarEngine[sTrueVarID];
}
else
{
return this.m_oVarEngine[sFalseVarID];
}
}
/**//**//**//// <summary>
/// Evaluates the Expression and returns the result in a Variable.
/// </summary>
/// <param name="expr">Expression to evaluate</param>
/// <returns>a Variable containing the result of the expression</returns>
public Variable RunExpression(string expr)
{
this.m_oExprMachine.Resolve(expr, m_oVarEngine);
Variable oRetVar = new Variable();
oRetVar.StringValue = m_oExprMachine.StringResult;
return oRetVar;
}
#endregion
Trigger methodsTrigger methods#region Trigger methods
/**//**//**//// <summary>
/// Gets trigger at index
/// </summary>
/// <param name="i">index</param>
/// <returns>Trigger object at index</returns>
public Trigger GetTrigger(int i)
{
return m_oTriggers[i];
}
/**//**//**//// <summary>
/// Get Trigger by ID
/// </summary>
/// <param name="sTriggerID">Id of Trigger</param>
/// <returns>Trigger by ID</returns>
public Trigger GetTrigger(string sTriggerID)
{
return m_oTriggers[sTriggerID];
}
/**//**//**//// <summary>
/// Gets the number of Triggers
/// </summary>
/// <returns>count of triggers</returns>
public int GetTriggerCount()
{
return m_oTriggers.Count;
}
/**//**//**//// <summary>
/// Runs the Rule associated with the Variable Id
/// </summary>
/// <param name="sVarID"></param>
private void CheckTrigger(string sVarID)
{
Trigger oTrigger = m_oTriggers[sVarID];
if(oTrigger != null)
{
RunRule(oTrigger.RuleID);
}
}
#endregion
List managementList management#region List management
/**//**//**//// <summary>
/// Adds a RuleObject to the RulesEngine
/// </summary>
/// <remarks>
/// If the RuleObject already Exists the RuleObject will be overwritten.
/// </remarks>
/// <param name="oRule">The RuleObject to Add</param>
public void Add(RuleObject oRule)
{
m_oRWLock.AcquireWriterLock(m_iTimeout);
try
{
int iFindIndexOf = FindIndexOf(oRule.ID);
// RuleObject with ID is not found now find where it belongs and insert it.
if(iFindIndexOf < 0)
{
RuleObject oProbe = new RuleObject();
int high = List.Count, low = -1, probe;
while (high - low > 1)
{
probe = (high + low) / 2;
oProbe = (RuleObject) List[probe];
if (oProbe.CompareTo(oRule.ID) < 0)
low = probe;
else
high = probe;
}
if(low < 0)
{
low = 0;
}
List.Insert(high, oRule);
this.AddInference(oRule);
}
else
{
//List[iFindIndexOf] = oRule;
throw new DuplicateRuleIDException(oRule.ID);
}
}
finally
{
m_oRWLock.ReleaseWriterLock();
}
}
/**//**//**//// <summary>
/// Adds and Array of RuleObjects to the RulesEngine.
/// </summary>
/// <remarks>
/// Only RuleObject in the ArrayList will be added.
/// </remarks>
/// <param name="oArrayList">ArrayList to add from</param>
public void AddAll(ArrayList oArrayList)
{
m_oRWLock.AcquireWriterLock(m_iTimeout);
try
{
foreach(RuleObject ruleObj in oArrayList)
{
Add(ruleObj);
}
}
finally
{
m_oRWLock.ReleaseWriterLock();
}
}
/**//**//**//// <summary>
/// Inserts a RuleObject at the Index
/// </summary>
/// <param name="index">int Index</param>
/// <param name="oRule">RuleObject to insert</param>
public void Insert(int index, RuleObject oRule)
{
m_oRWLock.AcquireWriterLock(m_iTimeout);
try
{
List.Insert(index, oRule);
}
finally
{
m_oRWLock.ReleaseWriterLock();
}
}
/**//**//**//// <summary>
/// Removes RuleObject
/// </summary>
/// <param name="oRule">RuleObject to remove</param>
public void Remove(RuleObject oRule)
{
m_oRWLock.AcquireWriterLock(m_iTimeout);
try
{
List.Remove(oRule);
}
finally
{
m_oRWLock.ReleaseWriterLock();
}
}
/**//**//**//// <summary>
/// Determines if a RuleObject exists
/// </summary>
/// <param name="oRule">RuleObject to check for</param>
/// <returns>True if found and False otherwise</returns>
public bool Contains(RuleObject oRule)
{
m_oRWLock.AcquireReaderLock(m_iTimeout);
try
{
return List.Contains(oRule);
}
finally
{
m_oRWLock.ReleaseReaderLock();
}
}
/**//**//**//// <summary>
/// Gets the Index of a RuleObject
/// </summary>
/// <param name="oRule">The RuleObject to get the Index of</param>
/// <returns>the index of the RuleObject</returns>
public int IndexOf(RuleObject oRule)
{
m_oRWLock.AcquireReaderLock(m_iTimeout);
try
{
return List.IndexOf(oRule);
}
finally
{
m_oRWLock.ReleaseReaderLock();
}
}
/**//**//**//// <summary>
/// Copies the Array to the RuleObject List
/// </summary>
/// <param name="array">The Variable Array to copy</param>
/// <param name="index">The starting index.</param>
public void CopyTo(Variable[] array, int index)
{
m_oRWLock.AcquireWriterLock(m_iTimeout);
try
{
List.CopyTo(array, index);
}
finally
{
m_oRWLock.ReleaseWriterLock();
}
}
/**//**//**//// <summary>
/// Re-Sorts Rule Collection
/// </summary>
public void ReSort()
{
ArrayList arr = new ArrayList(List);
List.Clear();
this.AddAll(arr);
}
#endregion
IndexerIndexer#region Indexer
/**//**//**//// <summary>
/// Indexer of RuleObject by int Index
/// </summary>
public RuleObject this[int index]
{
get
{
m_oRWLock.AcquireReaderLock(m_iTimeout);
try
{
return (RuleObject)List[index];
}
finally
{
m_oRWLock.ReleaseReaderLock();
}
}
set
{
m_oRWLock.AcquireWriterLock(m_iTimeout);
try
{
List[index] = value;
}
finally
{
m_oRWLock.ReleaseWriterLock();
}
}
}
/**//**//**//// <summary>
/// Indexer of RuleObject by String ID
/// </summary>
public RuleObject this[string sID]
{
get
{
return Find(sID);
}
set
{
int iFound = FindIndexOf(sID);
if(iFound >= 0)
{
List[iFound] = value;
}
}
}
#endregion
Find and SortFind and Sort#region Find and Sort
/**//**//**//// <summary>
/// Finds the RuleObject by its ID
/// </summary>
/// <param name="strTarget">The ID of the RuleObject to find</param>
/// <returns>The RuleObject if found and Null otherwise</returns>
public RuleObject Find(string strTarget)
{
m_oRWLock.AcquireReaderLock(m_iTimeout);
try
{
if(List.Count <= 0)
{
throw new RuleNotFoundException(strTarget);
}
else if(List.Count == 1)
{
return (RuleObject) List[0];
}
RuleObject oRetVar = new RuleObject();
RuleObject oProbe = new RuleObject();
int high = List.Count, low = -1, probe;
while (high - low > 1)
{
probe = (high + low) / 2;
oProbe = (RuleObject) List[probe];
if (oProbe.CompareTo(strTarget) < 0)
low = probe;
else
high = probe;
}
if(high == List.Count)
{
throw new RuleNotFoundException(strTarget);
}
else
{
oRetVar = (RuleObject) List[high];
if(oRetVar.CompareTo(strTarget) == 0)
{
return oRetVar;
}
else if(oRetVar.CompareTo(strTarget) < 0)
{
throw new RuleNotFoundException(strTarget);;
}
else
{
throw new RuleNotFoundException(strTarget);
}
}
}
finally
{
m_oRWLock.ReleaseReaderLock();
}
}
/**//**//**//// <summary>
/// Return the Index of a RuleObject whose ID matches the string Target
/// </summary>
/// <param name="strTarget">The string ID of the RuleObject to find</param>
/// <returns>the int index of the RuleObject if it is found and -1 if it is not found.</returns>
public int FindIndexOf(string strTarget)
{
m_oRWLock.AcquireReaderLock(m_iTimeout);
try
{
if(List.Count <= 0)
{
return -1;
}
RuleObject oRetVar = new RuleObject();
RuleObject oProbe = new RuleObject();
int high = List.Count, low = -1, probe;
while (high - low > 1)
{
probe = (high + low) / 2;
oProbe = (RuleObject) List[probe];
if (oProbe.CompareTo(strTarget) < 0)
low = probe;
else
high = probe;
}
if(low < 0)
{
low = 0;
}
if (high == List.Count)
{
return -1;
}
else
{
oRetVar = (RuleObject) List[high];
if(oRetVar.CompareTo(strTarget) > 0)
{
return -1;
}
else if(oRetVar.CompareTo(strTarget) == 0)
{
return high;
}
else
{
return low;
}
}
}
finally
{
m_oRWLock.ReleaseReaderLock();
}
}
#endregion
}
}