I'm looking to get a value from an
var guid = Guid.Parse("SOMEGUID-GUID-GUID-GUID-SOMEGUIDGUID");
Expression<Func<Someobject, bool>> selector = x => x.SomeId == guid;
For logging purposes I need to be able to fish out that guid.
I tried the following code, which I feel 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 exposes a member 'Value', which does contain what I'm looking for, but I'm a bit puzzled how to actually extract this.
And no:
var val = (Guid)constantExpression.Value;
Does not work :)
SOLVED
The end result looks like:
BinaryExpression binaryExpression = (BinaryExpression)selector.Body;
MemberExpression memberExpression = (MemberExpression)((UnaryExpression)binaryExpression.Right).Operand;
var myGuid = Expression.Lambda(memberExpression).Compile().DynamicInvoke();
Follow-up
I did some rudementary speed testing 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 out the compile version is MUCH slower. We're looking at a huge difference. (Timing is in ticks):
GetValueWithExpressionsAndReflection: Average over 100000, first call included: 0,93122
GetValueWithExpressionsAndReflection: First call: 851
GetValueWithExpressionsAndReflection: Average over 100000, first call excluded: 0,922719227192272
Versus:
GetValueWithCompiledExpression: Average over 100000, first call included: 499,53669
GetValueWithCompiledExpression: First call: 16818
GetValueWithCompiledExpression: Average over 100000, first call excluded: 499,373503735037
Rudementary tests or not: no doubt I will be using the reflection version. My results seem to be consistent with: http://www.minddriven.de/index.php/technology/dot-net/c-sharp/efficient-expression-values
Your const expression has 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 does this for you. Use a decompiler to check out the details.
Now you know how the expression tree looks like and you can decompose it. You'll need to use reflection to obtain the runtime value of the compilerGeneratedClass.guid
field or property.
This value is not part of the expression tree directly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With