LINQ功能类型参数中的lambdas如何工作



我已经使用了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>,因此可以推断TSourcePets。因此,它知道第二个参数的类型predicateFunc<Pets, bool>

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

由于TSourcePet型,因此应使用Func<Pet, bool>的编译器,因此Lambda具有pet类型的输入。这是Intellisense的来源。

因此,您要么指定类型(S)显式

pets.Any<Pet>(p => p.Age > 10);

隐式(由pets变量的编译器思维类型推断):

pets.Any(p => p.Age > 10);

最新更新