我正在努力熟悉表情樹,我正在撞牆。我希望能夠動態創建LINQ to XML查詢,所以我想讓自己熟悉Expression Trees。我從一個簡單的LINQ to XML語句開始,我希望能夠動態生成:
// sample data
var sampleData = new XElement("Items",
new XElement("Item", new XAttribute("ID", 1)),
new XElement("Item", new XAttribute("ID", 2)),
new XElement("Item", new XAttribute("ID", 3))
);
// simple example using LINQ to XML (hard-coded)
var resultsStatic = from item in sampleData.Elements("Item")
where item.Attribute("ID").Value == "2"
select item;
// trying to recreate the above dynamically using expression trees
IQueryable<XElement> queryableData = sampleData.Elements("Item").AsQueryable<XElement>();
ParameterExpression alias = Expression.Parameter(typeof(XElement), "item");
MethodInfo attributeMethod = typeof(XElement).GetMethod("Attribute", new Type[] { typeof(XName) });
PropertyInfo valueProperty = typeof(XAttribute).GetProperty("Value");
ParameterExpression attributeParam = Expression.Parameter(typeof(XName), "ID");
Expression methodCall = Expression.Call(alias, attributeMethod, new Expression[] { attributeParam });
Expression propertyAccessor = Expression.Property(methodCall, valueProperty);
Expression right = Expression.Constant("2");
Expression equalityComparison = Expression.Equal(propertyAccessor, right);
var resultsDynamic = queryableData.Provider.CreateQuery(equalityComparison);
我在調用CreateQuery時得到的錯誤是'Argument expression無效'。 equalityComparison的調試視圖顯示'(。Call $ item.Attribute($ ID))。值==“2”'。有人可以識別我做錯了嗎?
為了更好地理解正在發生的事情,請始終使用所需查詢的方法語法 。在你的情況下它是如下(我特別包括類型,雖然通常我會使用var
):
IQueryable<XElement> queryableData = sampleData.Elements("Item").AsQueryable();
IQueryable<XElement> queryStatic = queryableData
.Where((XElement item) => item.Attribute("ID").Value == "2");
現在讓我們看看你有什麼。
首先是attributeParam
變量
ParameterExpression attributeParam = Expression.Parameter(typeof(XName), "ID");
從靜態查詢中可以看出,屬性名稱沒有lambda參數 - 唯一支持的(和必需的)參數是item
(在代碼中由alias
變量表示)。所以這應該是XName
類型的ConstantExpression
,其值為“ID”:
var attributeParam = Expression.Constant((XName)"ID");
二, equalityComparison
變量。它包含的是item.Attribute("ID").Value == "2"
表達式。但是Where
方法需要Expression<Func<XElement, bool>>
,所以你必須使用equalityComparison
作為body和alias
作為參數創建:
var predicate = Expression.Lambda<Func<XElement, bool>>(equalityComparison, alias);
最後你必須調用Where
方法。你可以直接這樣做:
var queryDynamic = queryableData.Where(predicate);
或動態:
var whereCall = Expression.Call(
typeof(Queryable), "Where", new Type[] { queryableData.ElementType },
queryableData.Expression, Expression.Quote(predicate));
var queryDynamic = queryableData.Provider.CreateQuery(whereCall);
您可以查看使用過的Expression
方法文檔,了解它們的詳細信息。