linq函数类型参数中的lambdas如何工作?

时间:2016-06-22 15:51:23

标签: c# linq lambda

我已经使用了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的扩展方法的信息吗?

2 个答案:

答案 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>,因此可以推断TSourcePets。因此,它知道第二个参数predicate的类型是Func<Pets, bool>

第二部分是编译器将lambda语法识别为匿名函数,并且匿名函数可以隐式转换为兼容的委托类型或表达式树类型。这意味着您可以使用匿名函数,其中编译器期望FuncActionExpression或其他委托。所以在这种情况下,它认识到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);