編輯:更新了我正在做的事情的例子。
編輯2:原因:
我的班級“掌握”屬性設定者(或方法,匿名與否)並“控制”它一段時間。用戶可以嘗試附加我的類的另一個實例,並將其附加到已經“受控”的屬性。我需要一種可靠地檢測這些衝突的方法。我可以放棄()=> {property}方法,但這需要用戶將target屬性包裝在一個方法中,如果他/她想要衝突檢測,則傳入包含該屬性的對象。這樣做會帶來更高的bug風險,因為它們可能會輸入錯誤的對象,並且類沒有任何方法可以檢查它們。
我無法使用Lambda Compile(),因為除了JIT之外我還在瞄準AOT。
我有一個方法,需要一個
Expression<Func<T>>
作為一個論點。 Expression始終求值為類型為T的setter的屬性。
private static TargetInfo GetTargetInfo<T>(Expression<Func<T>> _propertyExpression, out Action<T> _setter)
{
//Get Property info
var propInfo = ((MemberExpression)_propertyExpression.Body).Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException("_propertyExpression must be a property.");
var declType = propInfo.DeclaringType;
var methodInfo = propInfo.GetSetMethod(true) ?? declType.GetProperty(propInfo.Name).GetSetMethod(true);
if (methodInfo == null)
throw new Exception("Could not create setter from property '" + _propertyExpression + "'");
var isStaticProp = methodInfo.IsStatic;
//Get Target Object
object targetObject = null;
var memberExp = _propertyExpression.Body as MemberExpression;
var bodyExp = memberExp.Expression;
if (bodyExp != null)
// PROBLEM LINE BELOW - Can't use Compile() *********************************
targetObject = Expression.Lambda<Func<object>>(bodyExp).Compile()();
// PROBLEM LINE ABOVE *******************************************************
else if (isStaticProp)
targetObject = memberExp.Member.DeclaringType;
else
throw new Exception("Could not determine target object. Use Action<T> overload. (no conflict detection)");
//Cache setter of property
if (isStaticProp)
_setter = (Action<T>) Delegate.CreateDelegate(typeof (Action<T>), methodInfo);
else
_setter = (Action<T>)Delegate.CreateDelegate(typeof(Action<T>), targetObject, methodInfo);
return new TargetInfo(methodInfo, targetObject);
}
表達式(_propertyExpression)始終是屬性。該物業總是有一個二傳手。
我需要該實例的原因是確定我的類的另一個對象實例當前是否正在該對像上使用該屬性SETTER。 (沒有線程,只是在一段時間內使用)我將對象實例和屬性設置器信息一起存儲為一個鍵,如果兩個相同的鍵存在則存在衝突並且它是根據用戶的配置設置來處理的。我的課。
我能夠獲得簡單表達式的對象實例,如:
() => MyProperty
要么
() => MyObjectInst.PropertyFoo
要么
() => MyStaticClass.PropertyFooBar
沒汗!
但是如果用戶這樣做會怎麼樣:
//Need instance of 'someObject' here.
() => SomeArray[idx].someObject.propertyA
或吹我的頂部:
//Need instance of 'someField[4]' here
() => SomeStaticClass.somePropertyList[5].SomeDictionary[objKey].SomeProperty.someFieldArray[4].propertyB
AAAK!
我已經看了一段時間,我相信我需要遍歷樹回到基礎對象(ConstantExpression)然後開始使用收集到的信息向前回到樹上。鑑於上面的例子我決定我需要“更大的槍支”。
有沒有更簡單的方法來獲取屬性的調用者的實例,而不是完全走樹而不使用Compile()?請解釋一下!
如果不是1.如果有人能指出我正確的方向如何遍歷樹和處理如上所述的東西。那太好了。我沒有找到關於遍歷表達式樹,表達式類型等的大量信息。即使是對特定於該主題的推薦書籍的引用也會有所幫助。
嘆氣我應該放棄並強迫用戶使用簡單的表達方式。即。不允許用戶鍵入冗長的屬性訪問行。
澄清:正在緩存setter以供機制類“FOO”使用,該機制類將在某個定義的時間段內將此值設置為類型T的UNKNOWN範圍。對象實例被緩存並用作鍵來檢測FOO的另一個實例嘗試附加並將值設置為該同一對像上的相同屬性的情況。對象實例用於檢測這些衝突,並且還用於跟踪附加到任何特定對象的所有“FOO”。用戶可以將多個“FOO”附加到同一對象,到不同的屬性。在用戶將FOO的實例附加到已經具有為該屬性附加的FOO的對像上的屬性的情況下,發生衝突事件。 FOO可以配置如何處理髮生的時間。
以下是您建議的方法存在的問題:
有沒有更簡單的方法來獲取屬性的調用者的實例,而不是完全走樹而不使用Compile()?請解釋一下!
簡短的回答,沒有。表達式意在編譯。進入.NET Funcs / Actions或其他一些平台(LINQ-to-Entities本質上將它們編譯成SQL)。如果你不想編譯它,你可能使用了錯誤的工具。
如果不是1.如果有人能指出我正確的方向如何遍歷樹和處理如上所述的東西。那太好了。我沒有找到關於遍歷表達式樹,表達式類型等的大量信息。即使是對特定於該主題的推薦書籍的引用也會有所幫助。
遍歷表達式樹的最佳方法是繼承ExpressionVisitor
。一個好的博客將是Matt Warren的博客http://blogs.msdn.com/b/mattwar/ ,閱讀有關實現IQueryable
的系列文章。但不,這並不容易。
人們可以(理論上)從ExpressionVisitor
繼承向下/向上走鏈接到原始實例。但是你必須以某種方式向上/向下走回鏈條,最簡單的方法是編譯子表達式。從理論上講,你可以使用Reflection來回過頭來,正如你的答案所嘗試的那樣,但是如果你的No-Compiling立場是鐵質的,我希望你明顯得到你選擇錯誤工具的印象。
嘆氣我應該放棄並強迫用戶使用簡單的表達方式。
你沒有概述這個的好處/缺點。