我已经使用了Linq一段时间了,在C#中使用了lambdas,但是我找不到lambdas如何意识到集合中的参数类型,因为对于方法来说,请说。任何(),如果我在此中做类似的事情,则来自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");
}
函数.yany()知道它具有lambda表达式内部pet类型的参数。但是,如果我做这样的事情:
(List<Pet> pets) => { return pets[0].Age; };
必须指定lambda中使用的类型。我认为类型是从集合内部获取的。有人可以提供有关如何从linq传递给扩展方法的数据类型的信息?
简单的答案是编译器为您执行此操作。
它通过两种不同的方法来执行此操作。第一个是称为类型推理的东西,它用于确定您方法的通用类型是什么。引用规格:
当调用一个通用方法而不指定类型参数时 类型推理过程尝试推断呼叫的类型参数。 类型推理的存在允许更方便的语法为 用于调用通用方法,并允许程序员避免 指定冗余类型信息。 - C#5 Spec
的N.5.2节
规格当然会精确地详细介绍了此过程的工作原理。
要在执行pets.Any(...)
时更仔细地查看您的情况。编译器将寻找有效的方法,并在枚举上找到以下匹配的扩展方法:
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>
,并且会适当编译。
在通用世界中,您指定了generic方法的类型隐式或显式(例如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的来源。
因此,您要么指定类型(S)显式:
pets.Any<Pet>(p => p.Age > 10);
或隐式(由pets
变量的编译器思维类型推断):
pets.Any(p => p.Age > 10);