Wenn ich ein Produkt habe.
var p = new Product { Price = 30 };
und ich habe die folgende linq Abfrage.
var q = repo.Products().Where(x=>x.Price == p.Price).ToList()
In einem IQueryable-Anbieter erhalte ich einen MemberExpression für den p.Price zurück, der einen konstanten Ausdruck enthält, aber ich kann den Wert "30" anscheinend nicht zurückbekommen.
Update Ich habe es versucht, aber es scheint nicht zu funktionieren.
var memberExpression = (MemberExpression)GetRootConstantExpression(m);
var fi = (PropertyInfo)memberExpression.Member;
var val = fi.GetValue(((ConstantExpression)memberExpression.Expression).Value, null);
Prost.
c#
linq
lambda
expression-trees
Schotime
quelle
quelle
expr
vom Typ habenExpression<Func<T>>
(der beispielsweiseexpr
den Ausdruck enthält() => myObj
),object exprValue = expr.Compile()();
führt der Einzeiler den Trick aus. Wirf es anschließend auf den gewünschten Typ. Nützlich in einigen Szenarien.quelle
DynamicInvoke
, am schnellsten sein kann @iggymoran hast du es getestet? Oder meintest du am schnellsten zu tippen? ;)Der konstante Ausdruck verweist auf eine vom Compiler generierte Capture-Klasse. Ich habe die Entscheidungspunkte usw. nicht angegeben, aber hier erfahren Sie, wie Sie 30 daraus erhalten:
var p = new Product { Price = 30 }; Expression<Func<Product, bool>> predicate = x => x.Price == p.Price; BinaryExpression eq = (BinaryExpression)predicate.Body; MemberExpression productToPrice = (MemberExpression)eq.Right; MemberExpression captureToProduct = (MemberExpression)productToPrice.Expression; ConstantExpression captureConst = (ConstantExpression)captureToProduct.Expression; object product = ((FieldInfo)captureToProduct.Member).GetValue(captureConst.Value); object price = ((PropertyInfo)productToPrice.Member).GetValue(product, null);
price
ist jetzt30
. Beachten Sie, dass ich davon ausgehe, dass diesPrice
eine Eigenschaft ist, aber in Wirklichkeit würden Sie eineGetValue
Methode schreiben , die Eigenschaft / Feld behandelt.quelle
Evaluate
undTryEvaluate
hier: code.google.com/p/protobuf-net/source/browse/trunk/…MemberExpression
dann auswertenden oder Erreichen desPropertyInfo/FieldInfo
dann auswertenden wie inTryEvaluate
?Die Verwendung
Expression.Lambda(myParameterlessExpression).Compile().Invoke()
hat mehrere Nachteile:.Compile()
ist langsam . Selbst bei kleinen Expressionsfragmenten kann es mehrere Millisekunden dauern, bis der Vorgang abgeschlossen ist. DerInvoke
Aufruf ist danach jedoch superschnell und benötigt nur wenige Nanosekunden für einfache arithmetische Ausdrücke oder Elementzugriffe..Compile()
generiert (emittiert) MSIL-Code. Das mag perfekt klingen (und erklärt die hervorragende Ausführungsgeschwindigkeit), aber das Problem ist: Dieser Code belegt Speicher, der nicht freigegeben werden kann, bevor die Anwendung beendet ist , selbst wenn der GC die Delegatenreferenz gesammelt hat!Man kann
Compile()
diese Probleme entweder ganz vermeiden, um sie zu vermeiden, oder die kompilierten Delegaten zwischenspeichern, um sie wiederzuverwenden. Diese kleine Bibliothek von mir bietet sowohl Interpretation vonExpressions
als auch im Cache gespeicherten Zusammenstellung , in der alle Konstanten und Schließungen des Ausdrucks durch zusätzliche Parameter automatisch ersetzt bekommen, die dann in einem Verschluss wieder eingesetzt, die an den Benutzer zurückgegeben wird. Beide Prozesse sind gut getestet, werden in der Produktion eingesetzt, haben Vor- und Nachteile, sind aber weit über 100-mal schneller alsCompile()
- und vermeiden den Speicherverlust!quelle
Wenn Sie eine Klasse hatten:
public class Item { public int Id { get; set; } }
und eine Instanz des Objekts:
var myItem = new Item { Id = 7 };
Sie können den Wert von Id mithilfe eines Ausdrucks mit dem folgenden Code abrufen:
Expression<Func<Item, int>> exp = x => x.Id; var me = exp.Body as MemberExpression; var propInfo = me.Member as PropertyInfo; var myValue = propInfo.GetValue(myItem, null);
myValue enthält "7"
quelle
value
ist eine reservierte Kennungq
ist vom TypList<Product>
. Die Liste hat keine Price-Eigenschaft - nur die einzelnen Produkte.Das erste oder letzte Produkt hat einen Preis.
Wenn Sie wissen, dass es nur eine in der Sammlung gibt, können Sie sie auch mit Single reduzieren
quelle
.ToList()
am Ende macht es in eine Liste.repo.Products.ToList()
ist definitiv eine ListeKönnen Sie Folgendes verwenden:
var price = p.Price; var q = repo.Products().Where(x=>x.Price == price).ToList()
quelle
Und was genau versuchst du zu erreichen?
Denn um auf den Wert von zuzugreifen
Price
, müssten Sie Folgendes tun:var valueOfPrice = q[0].Price;
quelle
Ab 2020
Diese Hilfsmethode ruft jeden Ausdruckswert ordnungsgemäß ab, ohne "Hack zu kompilieren":
public static object GetMemberExpressionValue (MemberExpression expression) { // Dependency chain of a MemberExpression is of the form: // MemberExpression expression // MemberExpression expression.Expression // ... MemberExpression expression.[...].Expression // ConstantExpression expression.[...].Expression.Expression <- base object var dependencyChain = new List<MemberExpression>(); var pointingExpression = expression; while (pointingExpression != null) { dependencyChain.Add(pointingExpression); pointingExpression = pointingExpression.Expression as MemberExpression; } if (!(dependencyChain.Last().Expression is ConstantExpression baseExpression)) { throw new Exception( $"Last expression {dependencyChain.Last().Expression} of dependency chain of {expression} is not a constant." + "Thus the expression value cannot be found."); } var resolvedValue = baseExpression.Value; for (var i = dependencyChain.Count; i > 0; i--) { var expr = dependencyChain[i - 1]; resolvedValue = new PropOrField(expr.Member).GetValue(resolvedValue); } return resolvedValue; }
PropOrField
Klasse:public class PropOrField { public readonly MemberInfo MemberInfo; public PropOrField (MemberInfo memberInfo) { if (!(memberInfo is PropertyInfo) && !(memberInfo is FieldInfo)) { throw new Exception( $"{nameof(memberInfo)} must either be {nameof(PropertyInfo)} or {nameof(FieldInfo)}"); } MemberInfo = memberInfo; } public object GetValue (object source) { if (MemberInfo is PropertyInfo propertyInfo) return propertyInfo.GetValue(source); if (MemberInfo is FieldInfo fieldInfo) return fieldInfo.GetValue(source); return null; } public void SetValue (object target, object source) { if (MemberInfo is PropertyInfo propertyInfo) propertyInfo.SetValue(target, source); if (MemberInfo is FieldInfo fieldInfo) fieldInfo.SetValue(target, source); } public Type GetMemberType () { if (MemberInfo is PropertyInfo propertyInfo) return propertyInfo.PropertyType; if (MemberInfo is FieldInfo fieldInfo) return fieldInfo.FieldType; return null; } }
quelle