ich eine grundlegende Regel-Engine, die ich in sehr ähnlicher Weise auf die Route gebaut haben hier vorgeschlagen:Bewertung komplexer Ausdrucksbaum
How to implement a rule engine?
Ive es auf der Grundlage weiterer Anforderungen erweitert, und jetzt brauche ich komplexe Klassen zB
EvaluateRule("Transaction.IsOpen", "Equals", "true")
Der Code in seiner einfachsten Form zu bewerten ist:
var param = inputMessageType;
left = Expression.Property(param, memberName);
tProp = typeof(T).GetProperty(r.MemberName).PropertyType;
right = Expression.Constant(Convert.ChangeType(r.TargetValue, tProp));
return Expression.MakeBinary(tBinary, left, right);
Um komplexe Klassen zu bewerten habe ich ein ähnliches Verfahren wie hier:
Das Problem, dass Im ist, dass wenn ich versuche, die Regel mit einer Eigenschaft einer Klasse (Transaction.IsOpen) zu bewerten , Ich bekomme es mit dem Typ des Stammtyps auf der rechten Seite des Ausdrucks, aber den Typ des komplexen Objekts auf der linken Seite des Ausdrucks.
Dies führt zu dem Fehler:
System.InvalidOperationException: The binary operator Equal is not defined for the types 'System.Func`2[Transaction,System.Boolean]' and 'System.Boolean'.
Wie überwinden ich dieses Problem? Ich bin kein Experte mit Expression Trees, und viele der Konzepte sind schwer zu verstehen, wenn das Beispiel von der Standarddokumentation abweicht.
Edit: Hier ist der Code (Ive weggelassen einige Sachen, die Umgebung spezifisch ist, um Fokus mit dem Problem halten)
public Actions EvaluateRulesFromMessage(ClientEventQueueMessage message)
{
var ruleGroups = _ruleRepository.GetRuleList();
var actions = new Actions();
foreach (var ruleGroup in ruleGroups)
{
if (message.MessageType == "UI_UPDATE")
{
// clean up json object
JObject dsPayload = (JObject.Parse(message.Payload));
var msgParams = JsonConvert.DeserializeObject<UiTransactionUpdate>(message.Payload);
msgParams.RulesCompleted = msgParams.RulesCompleted ?? new List<int>();
var conditionsMet = false;
// process the rules filtering out the rules that have already been evaluated
var filteredRules = ruleGroup.Rules.Where(item =>
!msgParams.RulesCompleted.Any(r => r.Equals(item.Id)));
foreach (var rule in filteredRules)
{
Func<UiTransactionUpdate, bool> compiledRule = CompileRule<UiTransactionUpdate>(rule, msgParams);
if (compiledRule(msgParams))
{
conditionsMet = true;
}
else
{
conditionsMet = false;
break;
}
}
if (conditionsMet)
{
actions = AddAction(message, ruleGroup);
break;
}
}
}
return actions;
}
public Func<UiTransactionUpdate, bool> CompileRule<T>(Rule r, UiTransactionUpdate msg)
{
var expression = Expression.Parameter(typeof(UiTransactionUpdate));
Expression expr = BuildExpr<UiTransactionUpdate>(r, expression, msg);
// build a lambda function UiTransactionUpdate->bool and compile it
return Expression.Lambda<Func<UiTransactionUpdate, bool>>(expr, expression).Compile();
}
static Expression Eval(object root, string propertyString, out Type tProp)
{
Type type = null;
var propertyNames = propertyString.Split('.');
ParameterExpression param = Expression.Parameter(root.GetType());
Expression property = param;
string propName = "";
foreach (var prop in propertyNames)
{
property = MemberExpression.PropertyOrField(property, prop);
type = property.Type;
propName = prop;
}
tProp = Type.GetType(type.UnderlyingSystemType.AssemblyQualifiedName);
var param2 = MemberExpression.Parameter(tProp);
var e = Expression.Lambda(property, param);
return e;
}
static Expression BuildExpr<T>(Rule r, ParameterExpression param, UiTransactionUpdate msg)
{
Expression left;
Type tProp;
string memberName = r.MemberName;
if (memberName.Contains("."))
{
left = Eval(msg, memberName, out tProp);
}
else
{
left = Expression.Property(param, memberName);
tProp = typeof(T).GetProperty(r.MemberName).PropertyType;
}
ExpressionType tBinary;
if (ExpressionType.TryParse(r.Operator, out tBinary))
{
Expression right=null;
switch (r.ValueType) ///todo: this needs to be refactored to be type independent
{
case TargetValueType.Value:
right = Expression.Constant(Convert.ChangeType(r.TargetValue, tProp));
break;
}
// use a binary operation ie true/false
return Expression.MakeBinary(tBinary, left, right);
}
else
{
var method = tProp.GetMethod(r.Operator);
var tParam = method.GetParameters()[0].ParameterType;
var right = Expression.Constant(Convert.ChangeType(r.TargetValue, tParam));
// use a method call, e.g. 'Contains' -> 'u.Tags.Contains(some_tag)'
return Expression.Call(left, method, right);
}
}
Wie funktioniert Ihre aktuellen Code-Look jetzt? –
Die linke Zuweisung in meinem Basiscode verwendet im Wesentlichen Code ähnlich der Antwort in der unteren Verknüpfung. das ist ziemlich viel, was den Fehler produziert - ich verstehe, warum ich den Fehler bekomme, ich brauche nur eine Strategie, um es zu überwinden – KerSplosh
Blick auf den Mitgliedsnamen, wenn es ein "enthält." ... wenn ja, können Sie die Punkte teilen und verschachtelte MemberExpressions machen ... https://msdn.microsoft.com/en-us/library/system.linq.expressions.memberexpression(v=vs.110). aspx – DarkSquirrel42