我正在考虑创建一个动态linq查询,其中Where
运算符将根据用户的选择而有所不同,而且我对框架不太熟悉。似乎我需要使用 Func
运算符,并且我很难理解这种语法。
它有什么作用? 什么意思?有人可以帮助我了解它是如何使用的吗?
谢谢。
Func<>
只是一个预定义的委托模式:
protected bool SomeMethod(int input)
{
return true;
}
这是一种相当标准的方法。您可以创建一个以此签名为目标的委托,如下所示:
public delegate bool MyMethodType(int input);
此委托仅适用于采用 1 个整数并返回布尔值的方法。Func<>试图通过使其通用来简化这一点:
public delegate T Func<T>();
public delegate U Func<T, U>(T input);
这实际上就是 Func<>,只是一个通用委托。这样,你可以说出所有这些事情:
Func<int, bool> myMethod = SomeMethod;
MyMethodType myMethod = SomeMethod;
就 LINQ 而言,您可能会使用速记表达式语法;编译器会将表达式转换为委托:
.Where(x => x.SomeProperty > 10);
此语句等效于:
.Where(delegate(int someProperty) { return someProperty > 10) })
这都是编译器语法糖。
Func<T>
只是一个类型名称。它不是一种特殊的语法。
您需要考虑的是 lambda 表达式。例如,考虑一下:
myCollection.Where(item => item.Size == 10)
这意味着以下内容:获取集合myCollection
中的所有项,检查每个项的Size
属性是否等于10
,并仅考虑这种情况的项。
更多这样的运算符使用 lambda 表达式。MSDN上的LINQ查询有一个很好的介绍。
只需记住Func<>
的意思是"功能"。函数基本上是一个返回结果的方法。
例如:
-
Func<bool>
的意思是"一个函数返回布尔值" -
Func<string,bool>
的意思是"一个函数仅将字符串作为输入参数并返回布尔" -
Func<bool,string,int,string,bool>
表示"一个函数需要 4 个输入参数分别为类型布尔值,字符串,整数和字符串...返回布尔值"
依此类推:<>
之间列出的类型是按正确顺序排列的输入参数类型,除了最后一个是函数的返回类型。
现在,就Where
而言,它需要一个Func<TSource, Boolean>
作为论据,对吧?这意味着任何采用TSource
输入参数并返回Boolean
(又名bool
)的方法都可以(TSource
是集合中每个元素的类型Where
)。
这意味着:Where
将只保留所选方法将返回true
的每个TSource
。
例:您希望筛选名字列表以仅保留以"T"开头的名字。
string[] firstnames = new string[] { "Albert", "Terry", "Bob", Tom", "Joe" };
string[] firstnamesBeginningWithT = firstnames.Where(beginsWithT).ToArray();
beginsWithT
是这种方法:
bool beginsWithT(string firstname)
{
return firstname.StartWith("T");
}
存在一种快捷方式,这使得创建此单行方法变得不必要beginsWithT
该方法可能只使用一次:
string[] firstnamesBeginningWithT = firstnames.Where(firstname => firstname.StartWith("T")).ToArray();
这意味着"对于集合中的每个元素,让我们通过方便将其称为firstname
,让我们看看它是否以 T 开头"。此语法调用"lambda 表达式",等效于"没有名称的即时方法",但与beginsWithT
一样,您会注意到它将string
作为输入并返回Boolean
。因此,它是一种Func<string,bool>
,符合Where
的需要。
希望现在一切都更清楚了! :-)西特拉
Func
不是运算符 - 它只是一个泛型委托类型。如果你看一下不同"重载"的签名,它应该会变得更加清晰:
Func<TResult>
Func<T, TResult>
Func<T1, T2, TResult>
第一个是不带参数并返回值的函数,第二个是接受一个参数并返回一个值的函数,依此类推。
总而言之,它本质上是一个帮助程序类型,使你能够定义函数,而无需每次都单独定义委托类型。
现在,这些对动态 Linq 查询都没有多大帮助,但这就是您提出的......
Func<T>
只是一个类型名称。它不是一种特殊的语法。
你需要把你的头缠绕在表达式树上。例如,考虑一下:
myCollection.Where(item => item.Size == 10)
如果myCollection
的类型为 IQueryable<T>
,则编译器会将其转换为表示 lambda 表达式item => item.Size == 10
的表达式树。例如,如果您使用它来访问 SQL 数据库,则此表达式会自动转换为 SQL。
可以使用表达式树生成动态查询,如 MSDN 中所述。特别是,您将使用 Expression
类型中的许多静态方法来动态构造此类表达式树。