我想動態構建一個 LINQ 查詢,這樣我就可以做類似的事情
var list = n.Elements().Where(getQuery("a", "b"));
代替
var list = n.Elements().Where(e => e.Name = new "a" || e.Name == "c");
(大多數情況下,我需要使用命名空間傳遞 XNames,而不僅僅是本地名稱......)
我的問題是訪問陣列元素:
private static Func<XElement, bool> getQuery(XName[] names)
{
var param = Expression.Parameter(typeof(XElement), "e");
Expression exp = Expression.Constant(false);
for (int i = 0; i < names.Length; i )
{
Expression eq = Expression.Equal(
Expression.Property(param, typeof(XElement).GetProperty("Name")!.Name),
/*--->*/ Expression.Variable(names[i].GetType(), "names[i]")
);
}
var lambda = Expression.Lambda<Func<XElement, bool>>(exp, param);
return lambda.Compile();
}
顯然 Variable 運算式是錯誤的,但是我很難構建一個能夠訪問陣列值的運算式。
uj5u.com熱心網友回復:
你需要創建一個運算式并編譯它嗎?除非我遺漏了一些細微差別,否則您只需要一個回傳Func<XElement, bool>.
private Func<XElement, bool> GetQuery(params string[] names)
{
return element => names.Any(n => element.Name == n);
}
這需要一個字串陣列并回傳一個Func<XElement>. 如果元素名稱與任何引數匹配,則該函式回傳 true。
然后您可以按照您的描述使用它:
var list = n.Elements.Where(GetQuery("a", "b"));
有很多方法可以做這樣的事情。為了提高可讀性,像這樣的擴展可能會更好:
public static class XElementExtensions
{
public static IEnumerable<XElement> WhereNamesMatch(
this IEnumerable<XElement> elements,
params string[] names)
{
return elements.Where(element =>
names.Any(n => element.Name == n));
}
}
那么使用它的代碼就變成了
var list = n.Elements.WhereNamesMatch("a", "b");
當我們的 LINQ 查詢中有其他過濾器時,這尤其有用。所有Where方法和其他方法都可能變得難以閱讀。但是,如果我們將它們隔離為具有明確名稱的自己的函式,則用法更易于閱讀,并且我們可以在不同的查詢中重用擴展。
uj5u.com熱心網友回復:
如果你想把它寫成 Expression 你可以這樣做:
public static Expression<Func<Person, bool>> GetQuery(Person[] names)
{
var parameter = Expression.Parameter(typeof(Person), "e");
var propertyInfo = typeof(Person).GetProperty("Name");
var expression = names.Aggregate(
(Expression)Expression.Constant(false),
(acc, next) => Expression.MakeBinary(
ExpressionType.Or,
acc,
Expression.Equal(
Expression.Constant(propertyInfo.GetValue(next)),
Expression.Property(parameter, propertyInfo))));
return Expression.Lambda<Func<Person, bool>>(expression, parameter);
}
是否編譯運算式取決于您要實作的方式。如果您想將運算式傳遞給查詢提供程式(參見Queryable.Where)并讓例如資料庫過濾您的值,那么您可能無法編譯該運算式。
如果要過濾記憶體中的集合,即列舉所有元素(參見Enumerable.Where)并將謂詞應用于所有元素,則必須編譯運算式。在這種情況下,您可能不應該使用 Expression api,因為這會增加代碼的復雜性,然后您更容易受到運行時錯誤的影響。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/392402.html
下一篇:無法將宿主物件編組到解釋器空間
