在C#中,"=> "符号的含义是什么?

7

有一个名为Student的类,它具有属性IdNamePhone。 在UI表单中,以以下方式列出了Student列表:

List<Student> students=new List<Student>();

最后,这是 dataGridview_Cellclick 事件的代码,在此处使用以下代码:

string id = dataGridview.Rows[e.RownIndex].Cells[0].Value.ToString();  
Student aStudent = students.Find(i=> i.Id== id);
< p > students.Find(i=> i.Id== id)是什么?它的意思是什么?=>符号的含义是什么?它是如何工作的?


3
Lambda表达式(C#编程指南)Lambda表达式是一种用于创建委托或表达式树类型的匿名函数。它提供了一种更简洁、更便捷的语法形式,可用于替代传统的委托或表达式树构造方法。Lambda表达式的语法形式如下:(parameter-list) => expression其中,参数列表指定了匿名函数的参数,箭头符号“=>”分隔参数列表和表达式,表达式则定义了匿名函数的执行动作。在使用Lambda表达式时,通常需要先定义一个委托类型或表达式树类型,用于接收Lambda表达式所创建的委托或表达式树实例。Lambda表达式还支持一些高级特性,如捕获外部变量、多行语句块以及异步调用等。总的来说,Lambda表达式是C#语言中非常强大且灵活的一种编程技巧,可以大大提高代码的简洁性和可读性。 - L.B
3
你对 代表 这个概念的理解程度有多少?请直接回答。 - Jon Skeet
@Jigar 为什么要添加一个 [anatomy] 标签?那个标签甚至不存在,也与问题不符。 - CodesInChaos
我尽力详细回答了你的子问题。如果有需要进一步解释的地方,请告诉我! - Miltos Kokkonidis
6个回答

4
他们被称为Lambda表达式...Lambda表达式使用特殊的语法。它们允许将函数用作数据,例如变量或字段。Lambda表达式语法使用=>运算符。这将匿名函数的参数和语句体分开。
你可以将其视为“转到”。
=>运算符可以被读作“转到”,并且在声明Lambda表达式时始终使用。Lambda表达式允许您将具有可执行语句的函数用作参数、变量或字段。
请参见MSDN上的this link以更好地理解它。

2
说实话,“is belong to”这个短语对于lambda表达式来说并不是非常有用。 - Jon Skeet
“它们允许将函数用作数据,例如变量或字段。”-- 不,它们不是。在 lambda 表达式出现之前,使用委托类型就已经可以实现这一点了。Lambda 表达式只是使创建这些函数更容易了。 (编辑:也许你的意思是“它们允许函数使用数据,例如变量或字段。”?) - user743382

3

这是一个goes to运算符(或lambda运算符),在lambda表达式(创建匿名方法)中用于将输入变量与lambda主体分离。

在您的示例students.Find(i => i.Id== id)中,输入变量i进入lambda主体i.Id == id(即作为匿名方法参数传递)。


还需要查看您正在使用的List<T>.Find方法。它接受类型为T谓词,在您的情况下将是Predicate<Student>。 Predicate是一个委托,表示定义一组条件并确定指定对象是否满足这些条件的方法。它具有以下签名:

public delegate bool Predicate<in Student>(Student obj)

所以,你需要传递一个接受学生对象并返回布尔值的方法。你可以为此创建普通命名方法:

private bool IsStudentHasIdEqualTo5(Student s)
{
   return s.Id == 5;
}

并且这样使用它:

Student aStudent = students.Find(IsStudentHasIdEqualTo5);

但是你需要验证不同的id值。有两个选项 - 要么在你的类中创建一个字段,在学生谓词方法内可用,要么创建一个既有这个方法又有这个字段的类:

class StudentSearcher
{
    private int _id; // capture id

    public StudentSearcher(int id)
    {
        _id = id;
    }

    // method has same signature as bool Predicate(Student obj)
    public bool VerfyId(Student s)
    {
        return s.Id == _id;
    }
}

现在您可以使用这个命名方法并为学生验证提供不同的id值:
var searcher = new StudentSearcher(id);
Student aStudent = students.Find(searcher.VerfyId);

但是为每个搜索创建这样的方法和类并不是很高效。这就是为什么我们有委托(和Lambda表达式)。您可以在需要的地方创建没有名称(匿名)的方法,而无需声明新的命名方法,编译器将为您生成常规的命名方法:

Student aStudent = students.Find(delegate(Student s) { 
                                      return s.Id == id; 
                                 });

同样的代码可以使用 lambda 语法编写 (省略 delegate 关键字,推断参数类型,使用 => 运算符分隔参数和方法体,同时省略 return 关键字):

Student aStudent = students.Find(s => s.Id == id);

这里的奇妙之处在于编译器会在幕后生成类,该类将具有谓词签名的方法,并且它还将具有用于捕获要搜索的 id 的字段。

1

lambda运算符将函数参数与其主体分开。

(arg1,arg2...argn)
=>
{
  //body
}

主体也可以没有括号..但它仍然是一个"主体"。

(arg1,arg2..argn) => 1 ;

Student aStudent = students.Find(i=> i.Id== id);

Find是一个接受Lambda表达式的Linq方法。

它将遍历students中的每个元素。

该元素由 i 表示,尽管student更有意义,并传递到“body”中。 如果i.Id==id,Find方法将返回student元素。


1
  • students.Find(i=> i.Id== id) 是什么意思?

情况是这样的。您有一个学生对象列表和您感兴趣的学生的ID。如果Student对象存储在您自己定义的集合中,该集合具有接受ID并返回具有该ID的学生的Find方法,则您的代码将如下所示:

Student aStudent = students.Find(id);

然而,当微软定义通用列表(List)集合时,他们不可能知道它将如何被使用--他们也不想知道。他们想要给你一个机会,让你能够使用它与Student对象或任何其他类型一起使用。但这意味着他们必须为你提供一种方法,通过提供只有你知道的关于你的问题的信息来找到你所需的元素。在这个特定的例子中,你知道你正在寻找一个存储在students列表中并且具有与你拥有的id匹配的Id字段的Student对象。如果我给你一个对象,让我们叫它i,你可以通过执行以下检查告诉我它是否是你正在寻找的对象:
i.Id == id 

如果我给你一个名为student的对象,你就可以执行测试student,通过执行测试告诉我它是否是你想要的那个。 student.Id == id (如果你没有id,但有其他唯一确定学生对象的信息(即键),你将需要指定不同的条件。灵活性很重要!)
所以,现在我们来到了下一个问题。
什么意思?
让我们创建一个约定。您将确定要称呼学生对象的名称,并提供适当的检查以选择您想要的学生。您将把表示该学生的标识符放在=>的左侧,将检查条件放在右侧。因此,您可以拥有类似以下内容的东西: student => student.Id == id 或者,如果您更喜欢用讨论中的学生对象i而不是student,则可以编写 i => i.Id == id

现在看一下。这是什么?它是一个给定学生对象并返回布尔值的函数!

  • =>符号的含义是什么?

    它是一个定义函数的运算符。参数在左侧,函数体在右侧。

  • 它是如何工作的?

    假设你想让我写一个函数,它接受一个列表参数和一个我们正在讨论的函数,并返回匹配的学生,而不使用Find方法。我可能会写出类似这样的代码:

    Student FindStudent(List students, Func match) { foreach(Student st in students) if(match(st)) return st; return st; }

    你可能会发现除了Func类型之外,其他都很熟悉。你可以想象Func是从学生到布尔值的一种函数类型。我也可以使用Predicate,你可以猜测它是用于学生谓词的一种类型。

    然而,你不需要让我写这个或者自己写这个,因为微软已经为我们写好了。List<T>类的Find()方法的代码看起来非常像上面的代码。

希望这有所帮助!


这应该涵盖了您所询问的所有内容。但为了获得更广泛的了解,您可能还想看一下:


以下是一些可能对您有帮助的提示:
  • lambda表达式可以有多个参数,例如`(x,y) => x*x + y + 43'
  • lambda表达式的右侧可以是代码块,例如`(x,y) => {return x*x + y + 43;}'
  • 具有字符串和整数参数并返回布尔值的lambda表达式的类型为`Func'
  • 具有一个字符串参数和一个整数参数且不返回任何内容的lambda表达式的类型为`Action'

1

=> 是一个 goesto 操作符,这个表达式是一个lambda表达式

请参见msdn


0

List<T> 定义了一个方法 Find(Predicate<T> match)

Predicate<T> 是一个委托,它可以引用任何与其签名匹配的方法。

bool Predicate(T param)

在您的情况下,您正在调用学生列表 List<Student> 上的 Find 方法,因此 Find 方法需要一个匹配以下签名的函数:

bool MyFindMethod(Student param)

你可以在你的类中定义这样一个方法:
bool MyFindMethod(Student param)
{
    // Logic goes here
}

并将其传递给您的Find方法,如下所示:

students.Find(MyFindMethod)

你正在使用的方法很小而简单,因此在你的类中创建一个方法的开销不值得,所以lambda表达式允许你以非常简洁的方式定义相同的方法。

s => s.Id == id

相当于:

bool AnonymousMethod(Student param)
{
    return s.Id == id;
}

=> 操作符左侧的项目是传递给方法的参数,右侧的项目是方法体。

请注意,编译器足够聪明,可以计算出参数(例如我的示例中的 s)的类型为 Student,因此不需要指定。

如果您有另一种类型的列表,例如:

public class Customer
{
    public string Name { get; set;}
}

public IList<Customer> customers = new List<Customer>();

那么编译器会推断参数的类型是Customer而不是学生。

customers.Find(c => c.Name == name);

请注意,参数可以命名为任何您想要的内容,但通常为了使表达简洁而保持为单个字母。
如果您理解了所有内容,那么您将会看到您的代码。
students.Find(i => i.Id == id)

基本上是调用一个以 Student 为参数的方法,并评估它是否与 => 运算符右侧的条件相匹配。如果参数满足条件(即,如果学生的 Idid 变量匹配),则表达式将返回 true。这告诉 Find 方法已经找到了匹配项,该对象将被返回。

我在这里回答了一个类似的与 WPF 相关的问题,但在不同上下文中的示例可能有助于您的理解。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接