我已经使用了Linq一段时间了,并且在C#中使用了lambdas,但是我无法知道lambda是如何知道集合中的参数类型的,因为,如果我做了什么,让我们说方法.Any()比如这个例子来自msdn:
class Pet
{
public string Name { get; set; }
public int Age { get; set; }
public bool Vaccinated { get; set; }
}
public static void AnyEx3()
{
// Create an array of Pets.
Pet[] pets =
{ new Pet { Name="Barley", Age=8, Vaccinated=true },
new Pet { Name="Boots", Age=4, Vaccinated=false },
new Pet { Name="Whiskers", Age=1, Vaccinated=false } };
// Determine whether any pets over age 1 are also unvaccinated.
bool unvaccinated =
pets.Any(p => p.Age > 1 && p.Vaccinated == false);
Console.WriteLine(
"There {0} unvaccinated animals over age one.",
unvaccinated ? "are" : "are not any");
}
函数.Any()知道它在lambda表达式中有一个Pet类型的参数。但如果我做这样的事情:
(List<Pet> pets) => { return pets[0].Age; };
必须指定lambda中使用的类型。我假设类型是从集合中获取的。有人可以提供有关如何将集合中的数据类型传递给Linq的扩展方法的信息吗?
答案 0 :(得分:3)
简单的答案是编译器会为你做这件事。
它通过两种不同的方法来实现。第一种是类型推断,它用于计算方法的泛型类型。引用规范:
当调用泛型方法而不指定类型参数时,a 类型推断过程尝试推断调用的类型参数。 类型推断的存在允许更方便的语法 用于调用泛型方法,并允许程序员避免 指定冗余类型信息。 - C#5规范的第N.5.2节
规范当然会详细说明这个过程的确切运作方式。
在执行pets.Any(...)
时,要更仔细地查看您的案例,编译器将查找有效的方法并在Enumerable上找到以下匹配的扩展方法:
public static bool Any<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate
)
在这种情况下,第一个参数是宠物。由于pets
实施IEnumerable<Pets>
,因此可以推断TSource
是Pets
。因此,它知道第二个参数predicate
的类型是Func<Pets, bool>
。
第二部分是编译器将lambda语法识别为匿名函数,并且匿名函数可以隐式转换为兼容的委托类型或表达式树类型。这意味着您可以使用匿名函数,其中编译器期望Func
,Action
,Expression
或其他委托。所以在这种情况下,它认识到lambda是Func<Pets, bool>
并且会适当地编译。
答案 1 :(得分:2)
在泛型世界中,您指定泛型方法的类型隐式或显式(例如TSource
),TSource
的所有其他用法都是类型。
Any
:public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
foreach (TSource element in source)
{
if (predicate(element))
{
return true;
}
return false;
}
}
由于TSource
的类型为Pet
,编译器会推断应使用Func<Pet, bool>
,因此lambda的输入类型为Pet。这是Intellisense的来源。
因此,您要么指定类型明确:
pets.Any<Pet>(p => p.Age > 10);
或隐含(由pets
变量的编译器思想类型推断):
pets.Any(p => p.Age > 10);