从ConstantExpression获取值

Ape*_*ron 6 c# reflection expression

我希望得到一个价值

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

为了记录目的,我需要能够捕获那个guid.

我尝试了下面的代码,我觉得它与我正在寻找的有些接近,但并不完全.

BinaryExpression binaryExpression = (BinaryExpression)selector.Body;
MemberExpression memberExpression = (MemberExpression)((UnaryExpression)binaryExpression.Right).Operand;
ConstantExpression constantExpression = (ConstantExpression)memberExpression.Expression;
Run Code Online (Sandbox Code Playgroud)

现在,ConstantExpression公开了一个成员'Value',它确实包含了我正在寻找的东西,但我有点疑惑如何实际提取它.

和不:

var val = (Guid)constantExpression.Value; 
Run Code Online (Sandbox Code Playgroud)

不起作用:)

解决了

最终结果如下:

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

跟进

我使用以下代码进行了一些粗略的速度测试:

    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);
    }
Run Code Online (Sandbox Code Playgroud)

原来编译版本慢得多.我们正在寻找一个巨大的差异.(时间是刻度):

GetValueWithExpressionsAndReflection:平均超过100000,首次调用包括:0,93122

GetValueWithExpressionsAndReflection:第一次调用:851

GetValueWithExpressionsAndReflection:平均超过100000,不包括第一个电话:0,922719227192272

与:

GetValueWithCompiledExpression:平均超过100000,首次调用包括:499,53669

GetValueWithCompiledExpression:第一次调用:16818

GetValueWithCompiledExpression:平均超过100000,不包括第一个电话:499,373503735037

是否进行粗略测试:毫无疑问,我将使用反射版本.我的结果似乎与以下内容一致:http: //www.minddriven.de/index.php/technology/dot-net/c-sharp/efficient-expression-values

usr*_*usr 2

您的 const 表达式具有 type EFAndExpressions.Program+<>c__DisplayClass0。这意味着该表达式具有以下结构:

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

编译器会为你做这件事。使用反编译器检查详细信息。

现在您知道表达式树是什么样子并且可以分解它了。您需要使用反射来获取字段compilerGeneratedClass.guid或属性的运行时值。

该值直接属于表达式树。