Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 表达式<;Func<;T>>;-获取属性';调用对象实例而不编译()_C#_Lambda_Expression Trees - Fatal编程技术网

C# 表达式<;Func<;T>>;-获取属性';调用对象实例而不编译()

C# 表达式<;Func<;T>>;-获取属性';调用对象实例而不编译(),c#,lambda,expression-trees,C#,Lambda,Expression Trees,编辑:更新了我实际正在做的示例 编辑2:原因: 我的类“掌握”属性设置器(或方法,匿名与否)并“控制”它一段时间。用户可以尝试附加我的类的另一个实例,并将其附加到已经“受控”的属性。我需要一种可靠地检测这些冲突的方法。我可以放弃()。这样做会带来更高的bug风险,因为它们可能键入错误的对象,而类将无法检查它们。 我无法使用Lambda Compile(),因为我的目标是JIT之外的AOT 我有一个方法需要 Expression<Func<T>> 或 或 不用担心 但

编辑:更新了我实际正在做的示例

编辑2:原因:
我的类“掌握”属性设置器(或方法,匿名与否)并“控制”它一段时间。用户可以尝试附加我的类的另一个实例,并将其附加到已经“受控”的属性。我需要一种可靠地检测这些冲突的方法。我可以放弃()。这样做会带来更高的bug风险,因为它们可能键入错误的对象,而类将无法检查它们。

我无法使用Lambda Compile(),因为我的目标是JIT之外的AOT


我有一个方法需要

Expression<Func<T>> 

不用担心

但是,如果用户这样做了呢:

//Need instance of 'someObject' here.
() => SomeArray[idx].someObject.propertyA
或者让我大吃一惊:

//Need instance of 'someField[4]' here
() => SomeStaticClass.somePropertyList[5].SomeDictionary[objKey].SomeProperty.someFieldArray[4].propertyB

我已经看了一段时间了,我认为我需要遍历树回到基本对象(ConstantExpression),然后开始使用收集到的信息来评估树的备份,然后向前走。鉴于上述例子,我决定我需要“更大的枪”

  • 除了在不使用Compile()的情况下完全遍历树之外,还有更容易获取属性调用方实例的方法吗?如果是,请解释

  • 如果不是1。如果有人能为我指出正确的方向,告诉我如何穿过这棵树并处理上面提到的事情。那太好了。我找不到关于遍历表达式树、表达式类型等的全部信息。即使是参考一本特定于该主题的推荐书也会有所帮助

  • 唉,我应该放弃,强迫用户使用简单的表达式。 也就是说,不允许用户输入冗长的财产访问行

  • 澄清:
    setter正在被缓存以供机制类“FOO”使用,该机制类将在某个定义的时间段内将该值设置为T类型的未知值范围。对象实例被缓存并用作键,以检测另一个FOO实例尝试将值附加到同一对象上的同一属性并将其设置为值的情况。对象实例用于检测这些冲突,还用于跟踪附加到任何特定对象的所有“FOO”。用户可以将多个“FOO”附加到同一对象的不同属性上。如果用户将一个FOO实例附加到已为该属性附加了FOO的对象上的属性,则会发生冲突事件。FOO可以配置为如何处理这种情况。

    我已经确认以下内容适用于MONO->iOS。。。至少在基础知识和阵列方面。我没能把字典/单子翻出来。AOT似乎不喜欢MethodInfo.Invoke

    编辑:

    我在MSDN上找到了这个答案:

    它遍历表达式树,根据需要计算树的每个部分,最后返回指定属性的包含对象

    输入此项(同时在中添加下面的方法代码):

    与此相反:

    targetObject = Expression.Lambda<Func<object>>(bodyExp).Compile()();
    
    targetObject=Expression.Lambda(bodyExp.Compile();
    
    在上面的代码中

    我还没有在其他平台上对其进行全面测试,我相信我会遇到其他需要添加更多案例的情况,但这可能足以帮助其他人,也足以让我继续前进,我会尝试在遇到更多情况时更新此内容:

    public static object GetContainer<T>(Expression<Func<T>> propertyLambdaExpression)
    {
        return Evaluate((propertyLambdaExpression.Body as MemberExpression).Expression);
    }
    public static object Evaluate(Expression e)
    {
        switch (e.NodeType)
        {
            case ExpressionType.Constant:
                return (e as ConstantExpression).Value;
            case ExpressionType.MemberAccess:
                {
                    var propertyExpression = e as MemberExpression;
                    var field = propertyExpression.Member as FieldInfo;
                    var property = propertyExpression.Member as PropertyInfo;
                    var container = propertyExpression.Expression == null ? null : Evaluate(propertyExpression.Expression);
                    if (field != null)
                        return field.GetValue(container);
                    else if (property != null)
                        return property.GetValue(container, null);
                    else
                        return null;
                }
            case ExpressionType.ArrayIndex: //Arrays
            {
                var arrayIndex = e as BinaryExpression;
                var idx = (int)Evaluate(arrayIndex.Right);
                var array = (object[])Evaluate(arrayIndex.Left);
                return array[idx];
            }
            case ExpressionType.Call: //Generic Lists and Dictionaries
            {
                var call = e as MethodCallExpression;
                var callingObj = Evaluate(call.Object);
                object[] args = new object[call.Arguments.Count];
                for (var idx = 0; idx < call.Arguments.Count; ++idx)
                    args[idx] = Evaluate(call.Arguments[idx]);
                return call.Method.Invoke(callingObj, args);
            }
            default:
                return null;
        }
    }
    
    公共静态对象GetContainer(表达式propertyLambdaExpression) { 返回Evaluate((propertyLambdaExpression.Body as MemberExpression).Expression); } 公共静态对象求值(表达式e) { 开关(例如节点类型) { 大小写表达式类型。常量: 返回(e为恒压)。值; case ExpressionType.MemberAccess: { var propertyExpression=e作为MemberExpression; var field=propertyExpression.Member作为FieldInfo; var property=propertyExpression.Member作为PropertyInfo; var container=propertyExpression.Expression==null?null:Evaluate(propertyExpression.Expression); 如果(字段!=null) 返回字段.GetValue(容器); else if(属性!=null) return property.GetValue(container,null); 其他的 返回null; } case ExpressionType.ArrayIndex://数组 { var arrayIndex=e作为二进制表达式; var idx=(int)Evaluate(arrayIndex.Right); var数组=(object[])Evaluate(arrayIndex.Left); 返回数组[idx]; } case ExpressionType.Call://通用列表和字典 { var call=e作为MethodCallExpression; var callingObj=Evaluate(call.Object); object[]args=新对象[call.Arguments.Count]; 对于(var idx=0;idx以下是您建议的方法的问题:

  • 是否有更简单的方法获取属性调用方的实例 而不是不使用Compile()完全遍历树?请 如果是,请解释

  • 答案很简单,不是。表达式是要编译的。可以放入.NET Funcs/Actions或其他平台(LINQ to实体实质上将它们编译成SQL)。如果您不想编译它,可能是使用了错误的工具

  • 如果不是1。如果有人能给我指出正确的方向 穿过树,处理像ab这样的东西
    //Need instance of 'someObject' here.
    () => SomeArray[idx].someObject.propertyA
    
    //Need instance of 'someField[4]' here
    () => SomeStaticClass.somePropertyList[5].SomeDictionary[objKey].SomeProperty.someFieldArray[4].propertyB
    
    targetObject = GetContainer(_propertyExpression);
    
    targetObject = Expression.Lambda<Func<object>>(bodyExp).Compile()();
    
    public static object GetContainer<T>(Expression<Func<T>> propertyLambdaExpression)
    {
        return Evaluate((propertyLambdaExpression.Body as MemberExpression).Expression);
    }
    public static object Evaluate(Expression e)
    {
        switch (e.NodeType)
        {
            case ExpressionType.Constant:
                return (e as ConstantExpression).Value;
            case ExpressionType.MemberAccess:
                {
                    var propertyExpression = e as MemberExpression;
                    var field = propertyExpression.Member as FieldInfo;
                    var property = propertyExpression.Member as PropertyInfo;
                    var container = propertyExpression.Expression == null ? null : Evaluate(propertyExpression.Expression);
                    if (field != null)
                        return field.GetValue(container);
                    else if (property != null)
                        return property.GetValue(container, null);
                    else
                        return null;
                }
            case ExpressionType.ArrayIndex: //Arrays
            {
                var arrayIndex = e as BinaryExpression;
                var idx = (int)Evaluate(arrayIndex.Right);
                var array = (object[])Evaluate(arrayIndex.Left);
                return array[idx];
            }
            case ExpressionType.Call: //Generic Lists and Dictionaries
            {
                var call = e as MethodCallExpression;
                var callingObj = Evaluate(call.Object);
                object[] args = new object[call.Arguments.Count];
                for (var idx = 0; idx < call.Arguments.Count; ++idx)
                    args[idx] = Evaluate(call.Arguments[idx]);
                return call.Method.Invoke(callingObj, args);
            }
            default:
                return null;
        }
    }