有一个名为Student
的类,其属性为Id
,Name
和Phone
。
在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);
students.Find(i=> i.Id== id)
做了什么?这是什么意思? =>
符号的含义是什么?它是如何工作的?
答案 0 :(得分:4)
它们称为Lambda表达式...... Lambda表达式使用特殊语法。它们允许将函数用作变量或字段等数据。 lambda表达式语法使用=&gt;运营商。这将分隔匿名函数的参数和语句体。
你可以将其作为&#34;转到&#34;。
=&gt;运算符可以读作&#34;转到&#34;并且在声明lambda表达式时始终使用它。 lambda表达式允许您将带有可执行语句的函数用作参数,变量或字段。
请参阅MSDN上的this link以更好地了解它。
答案 1 :(得分:3)
这是goes to
运算符(或lambda operator),它在lambda expressions(匿名方法创建)中用于将输入变量与lambda主体分开。
在您的示例中students.Find(i => i.Id== id)
输入变量i
转到lambda body i.Id == id
(即作为匿名方法参数传递)。
另请查看您正在使用的List<T>.Find
方法。它接受T
类型的predicate,在您的情况下为Predicate<Student>
。 Predicated是一个委托,它表示定义一组条件并确定指定对象是否满足这些条件的方法。它有以下签名:
public delegate bool Predicate<in Student>(Student obj)
因此,您需要传递一个方法,该方法接受一个学生对象并返回一个bool。您可以为此创建常规命名方法:
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);
但是为每次搜索创建这样的方法和类并不是很有效。这就是为什么我们有代表(和lambdas)。您可以在您需要的地方创建没有名称(匿名)的方法,而不是声明新的命名方法,编译器将为您生成通常的命名方法:
Student aStudent = students.Find(delegate(Student s) {
return s.Id == id;
});
完全相同的代码可以用lambda语法编写(委托关键字省略,参数类型推断,goes to
运算符用于分隔参数和方法体,return关键字也省略):
Student aStudent = students.Find(s => s.Id == id);
这里的神奇之处在于编译器将生成如上所示的类似于场景的类。该类将具有带谓词签名的方法,并且还将具有用于捕获id
以进行搜索的字段。
答案 2 :(得分:1)
=&gt; 是 goesto 运算符,此表达式为 lambda expresion
请参阅msdn
答案 3 :(得分:1)
lambda运算符将函数参数与其主体分开。
(arg1,arg2...argn)
=>
{
//body
}
身体也可能没有括号..但它仍然是一个“身体”。
(arg1,arg2..argn) => 1 ;
Student aStudent = students.Find(i=> i.Id== id);
Find是一个采用lambda表达式的Linq方法。
它将贯穿学生的每个元素。
元素由i
表示 - 虽然student
会更有意义 - 并且会被传递到“正文”中。
如果i.Id==id
,则Find方法会返回student
元素。
答案 4 :(得分:1)
students.Find(i=> i.Id== id)
做什么? 情况就是这样。您有一个学生对象列表和您感兴趣的学生的ID。如果学生对象存储在一个集合中,您自己定义了一个带有ID的Find方法并返回具有该id的学生,您的代码看起来像这样:
Student aStudent = students.Find(id);
然而,当微软定义了通用的List集合时,他们不可能知道如何使用它 - 而且他们不想知道。他们希望让您有机会将它与Student对象或您能想到的任何其他类型一起使用。但这意味着他们必须通过提供只有您知道的问题信息,为您提供一种方法来找到您所追求的元素。在这个特定的实例中,您知道您正在寻找存储在学生列表中的Student对象,该对象的Id字段与您拥有的ID相匹配。如果我给你一个对象,让我们称之为i
,你可以通过执行以下检查告诉我它是否是你要找的对象:
i.Id == id
如果我给你一个名为student
的对象,你就可以执行测试student
,你可以通过执行测试告诉我你是否是你所追求的那个1} p>
student.Id == id
(如果您没有id,但是其他一些信息唯一地确定了Student对象(即一个键),那么您需要指定一个不同的条件。灵活性非常重要!)
所以,现在我们到达下一个问题。
这是什么意思?
让我们创建一个约定。您将确定要将学生对象称为什么,然后您将提供一个适当的检查来挑选您所学的学生。您将代表该学生的标识符放在=>
的左侧,并将检查条件放在右侧。因此,你可以有类似的东西:
student =&gt; student.Id == id
或者如果您希望引用正在讨论的学生对象i
而不是student
,那么您可以写
i =&gt; i.Id == id
现在来看看。这是什么?给出一个Student对象返回一个bool。这是一个功能!
=&gt;是什么意思?标志?
它是一个定义函数的运算符。论点位于左侧,正文位于右侧。
它是如何运作的?
假设您希望我编写一个函数,该函数接受List参数和我们正在讨论的函数,并返回匹配的学生而不使用Find方法。我可能会写这样的东西。
学生FindStudent(列出学生,Func匹配) { foreach(学生) if(match(st))返回st; 返回 }
你可能会发现一切都很熟悉,但是,我想,你可以想象的类型Func是一种从学生到布尔的函数。我也可以使用Predicate,你可以猜测它是学生谓词的一种类型。
但是,你不需要我自己写这个或自己写这个,因为微软已经为我们做了这个。 Microsoft为Find()
类的List<T>
编写的代码与上述代码非常相似。
希望有所帮助!
这应该包括您提出的所有问题。但为了获得更广泛的图片,您可能还想看看:
可能对您有所帮助的一些分离说明:
答案 5 :(得分:0)
List<T>
定义了一种方法Find(Predicate<T> match)
。
Predicate<T>
是一个委托,可以引用与其签名
bool Predicate(T param)
在您的情况下,您在学生列表Find
上调用List<Student>
方法,因此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
,因此不需要指定。
如果您有其他类型的列表E.G。
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
作为参数并对其进行评估,以查看它是否与=>
运算符右侧的条件匹配。如果参数符合条件(即,如果学生Id
与id
变量匹配),则表达式将返回true。这告诉Find
方法它已找到匹配项并将返回此对象。
我回答了与WPF相关的类似问题here,但在不同背景下的示例可能有助于您理解。