Lambda 运算符的工作原理以及它如何简化 LINQ(c#) 中的表达式

本文关键字:LINQ 何简化 表达式 工作 运算符 Lambda | 更新日期: 2023-09-27 18:36:08

我是C#学习的新手,我无法清楚地理解lambda运算符,但我理解的是它简化了表达式。

 var testString = Console.ReadLine();
            testString.ToCharArray()
            .OrderBy(i => i).ToLookup(j => j)
            .Select(i => new Program { letter = i.Key, count = i.Count() }).ToList()
            .ForEach(i => Console.WriteLine("letter {0},count {1}", i.letter, i.count,i.sign));

在上面的代码中,我没有得到"i"和"j"。 这是匿名类型的变量还是对象?

Lambda 运算符的工作原理以及它如何简化 LINQ(c#) 中的表达式

问题是你的问题本身是错误的,你问"这是一个变量或对象还是匿名类型",就好像这 3 件事是不兼容的。匿名类型具有实例,这些实例是对象,引用这些对象所使用的名称是变量。但是,我将尝试澄清语法,以便对您更有意义。

要了解正在发生的事情,您必须查看所有那些花哨的 linq 运算符作为签名的内容,让我们以 OrderBy 为例:

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);

第一个参数是你调用orderby的对象(如果这让你感到困惑,谷歌向上扩展方法),另一个参数(对应于代码中的i=>i的参数)是这样的:

Func<TSource, TKey> keySelector

现在我们需要深入挖掘,看看"Func"是什么,我们来看看 Func 的定义:

public delegate TResult Func<in T, out TResult>(T arg)

Func 是 . . .委托定义!在引入 lambda 之前就已经存在的东西,现在我们知道 i => i 是 Wise 类型,我们可以尝试理解 i 是什么,为此我们需要剖析语法。我们知道 i => i 是一个委托函数,一旦我们推断出类型(通过知道你的枚举的类型),它的签名看起来像这样,在调用 orderby 之前和之后,你都在使用一个可枚举的 char,所以 i=>i 是一个 Func,它是一个委托 char Func(char Item),基本上是一个接受 char 的委托, 并返回一个字符。

Lambda 函数是在非常特定的情况下表达委托的一种非常简洁的方式,让我们看看您可以做到这一点的旧方法

char MyMethod(char c)
{
    return c;
}
bla.OrderBy(MyMethod); // This is a very verbose version, we defined an external method

现在,这种方式在大多数情况下是有意义的,因为您必须指定所有这些信息(在无法使用类型推断的非通用情况下)。但是,正如我之前所展示的,我们知道(由于推理)您从一开始就在处理 Func,这要归功于您调用它的对象的类型,这意味着我们可以剥离冗余信息并最终得到:

MyMethod(c)
{
   return c;
}

我们还能剥离什么?好吧,方法的名字!为什么?因为我们只使用它一次,所以如果它不会被重复使用,为什么要命名它!

(c){ return c;}

此外,您经常想做一些非常简单的事情,这些事情包含在单个语句中,所以为什么要费心返回它,让我们隐式返回语句解析的内容并删除括号! (三) 三

现在我们留下了一些与原始代码完全相同的东西(原始代码中的所有附加代码都是无用的,可以从上下文中推断出来,正如我所演示的那样),所以我们只需更改语法,通过在输入变量和代码之间添加 lambda 运算符 => 使其明显不同

(c)=>c

如果您仅通过删除 () 传入单个元素,则可以再次简化

c=>c

那么什么是 lambda 运算符?它是签名和代码之间的分隔符,整个表达式声明了一个while方法而不命名它,并且通过让编译器尽可能多地推断,内联到你结束的地方使用它在一个非常简洁的语法中。在您的例子中,i 是一个局部变量,作为您正在内联定义的委托的输入传入。

至于您在示例中未使用的匿名类型,它们是内联声明且未命名的类型,并且也意味着在查询范围内使用(就像 lambda 表达式避免为您不需要命名且不会重用的代码创建一次性函数一样,匿名类型避免为您只会使用一次的数据创建 1 个镜头类)。