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