Get value from constant expression

I want to get the value from

var guid = Guid.Parse("SOMEGUID-GUID-GUID-GUID-SOMEGUIDGUID"); Expression<Func<Someobject, bool>> selector = x => x.SomeId == guid; 

For logging, I need to catch this guid.

I tried the following code, which, in my opinion, is somewhat close to what I'm looking for, but not quite.

 BinaryExpression binaryExpression = (BinaryExpression)selector.Body; MemberExpression memberExpression = (MemberExpression)((UnaryExpression)binaryExpression.Right).Operand; ConstantExpression constantExpression = (ConstantExpression)memberExpression.Expression; 

Now ConstantExpression provides a 'Value' member that contains what I'm looking for, but I'm a bit puzzled by how to extract it.

And no:

 var val = (Guid)constantExpression.Value; 

Does not work:)

solvable

The end result is as follows:

 BinaryExpression binaryExpression = (BinaryExpression)selector.Body; MemberExpression memberExpression = (MemberExpression)((UnaryExpression)binaryExpression.Right).Operand; var myGuid = Expression.Lambda(memberExpression).Compile().DynamicInvoke(); 

Subsequent

I did some speed tests using the following code:

  static void Main(string[] args) { var id = Guid.Parse("bleh"); Expression<Func<Thingemebob, bool>> selector = x => x.Id == id; var tickList = new List<long>(); for (int i = 0; i < 100000; i++) { var sw = Stopwatch.StartNew(); GetValueWithExpressionsAndReflection(selector); sw.Stop(); tickList.Add(sw.ElapsedTicks); } Trace.WriteLine("GetValueWithExpressionsAndReflection: Average over 100000, first call included: " + tickList.Average()); Trace.WriteLine("GetValueWithExpressionsAndReflection: First call: " + tickList[0]); Trace.WriteLine("GetValueWithExpressionsAndReflection: Average over 100000, first call excluded: " + tickList.Skip(1).Average()); tickList = new List<long>(); for (int i = 0; i < 100000; i++) { var sw = Stopwatch.StartNew(); GetValueWithCompiledExpression(selector); sw.Stop(); tickList.Add(sw.ElapsedTicks); } Trace.WriteLine("GetValueWithCompiledExpression: Average over 100000, first call included: " + tickList.Average()); Trace.WriteLine("GetValueWithCompiledExpression: First call: " + tickList[0]); Trace.WriteLine("GetValueWithCompiledExpression: Average over 100000, first call excluded: " + tickList.Skip(1).Average()); Debugger.Break(); } private static void GetValueWithCompiledExpression(Expression<Func<Note, bool>> selector) { BinaryExpression binaryExpression = (BinaryExpression)selector.Body; MemberExpression memberExpression = (MemberExpression)((UnaryExpression)binaryExpression.Right).Operand; var o = Expression.Lambda(memberExpression).Compile().DynamicInvoke(); } private static void GetValueWithExpressionsAndReflection(Expression<Func<Note, bool>> selector) { BinaryExpression binaryExpression = (BinaryExpression)selector.Body; MemberExpression memberExpression = (MemberExpression)((UnaryExpression)binaryExpression.Right).Operand; ConstantExpression constantExpression = (ConstantExpression)memberExpression.Expression; FieldInfo member = (FieldInfo)memberExpression.Member; var instance = constantExpression.Value; var guid = member.GetValue(instance); } 

Turns off the MUCH compilation version more slowly. We look at the huge difference. (Dates in ticks):

GetValueWithExpressionsAndReflection: more than 100,000 on average, first call on: 0.93122

GetValueWithExpressionsAndReflection: First call: 851

GetValueWithExpressionsAndReflection: more than 100,000 on average, first call excluded: 0.922719227192272

Versus:

GetValueWithCompiledExpression: On average, more than 100,000, first call on: 499.53669

GetValueWithCompiledExpression: First call: 16818

GetValueWithCompiledExpression: on average more than 100,000, first call excluded: 499,373503735037

Trial tests or not: no doubt, I will use the reflection version. My results seem to be consistent with: http://www.minddriven.de/index.php/technology/dot-net/c-sharp/efficient-expression-values

+6
source share
1 answer

Your const expression is of type EFAndExpressions.Program+<>c__DisplayClass0 . This means that the expression has the following structure:

 var compilerGeneratedClass = new compilerGeneratedClass() { guid = Guid.Parse("SOMEGUID-GUID-GUID-GUID-SOMEGUIDGUID"); }; Expression<Func<Someobject, bool>> selector = x => x.SomeId == compilerGeneratedClass.guid; 

The compiler will do this for you. Use the decompiler to check the details.

Now you know what the expression tree looks like, and you can expand it. To get the runtime value of a field or compilerGeneratedClass.guid property, you must use reflection.

This value is not part of the expression tree directly.

+2
source

All Articles