List.Find()
原文链接:https://zhuanlan.zhihu.com/p/626069652
List.Find 的作用:寻找第一个 List 中第一个满足条件的元素的引用,当然如果是值类型,直接返回值。当然没找到肯定就返回 null 了。
判定是否“满足条件”需要依靠 List.Find 中委托类型的参数,我相信有部分人和我之前一样,可能没法完全理解这个参数到底该怎么填。先看一下官方定义:(如果还没学到委托的小伙伴,可以先去学习一下,简单来讲就是函数的容器,它可以保存许多函数的引用)
//官方文档定义,其中这个 T 是 C# 的泛型,它可以指代任何类型,就跟未知数 x 一样,可以指代任何数。
T List<T>.Find(Predicate<T> match);
//例如:用一个名为 MyClass 的类替代
MyClass List<MyClass>.Find(Predicate<MyClass> match);
首先这个参数 match 的类型是一个委托类型(delegate),但官方给出的定义是 Predicate<T>,这是C#提前写好的内置委托类型。(对于 泛型 T,以下都用 MyClass 替代)
这个 Predicate 就相当于以下委托, 也就是一个 返回bool类型,并且接收一个 MyClass 类型的参数 的委托。
public delegate bool Predicate(MyClass obj);
//以下是泛型写法
public delegate bool Predicate<in T>(T obj);
知道了这些,我们在回头看 List.Find。该函数会将列表中元素挨个作为上述委托的输入,然后根据委托的具体返回结果,如果返回 true 就判定找到,如果返回 false 就继续找。如果便历完所有元素还没有找到匹配的元素,就返回 null。
注:我们可以向委托 match 中添加多个判定函数,如果 Find 函数的参数 match 中有多个函数,那么只有当最后加入的函数返回 true 时才判定找到(这个是委托的定义:对于有返回值的委托,调用时默认返回最后加入函数的返回值),然后返回 List 该位置的值。所以在这种情况下,在向 委托match 中添加多个函数是没有意义的。
基础解析
MyTest 的定义,该类用替代上述泛型 T。
class MyTest
{
public int x = 1;
public MyTest(int x)
{
this.x = x;
}
}
MainClass:测试样例,在这个样例中我们定义了 Predicate类型的委托 pTest1,pTest2,并且分别给他们添加了函数 MyCondition1、MyCondition2 ,其中 MyCondition2 我们故意让其返回 false,也就说如果我们使用 pTest2 进行作为 List.Find 的参数的话,它一定返回 null。最后我们分别将 pTest1,pTest 作为 参数在 list 中查找,并通过 Console.WriteLine 来验证。
class MainClass
{
//定义成静态函数,是因为MainClass不会被实例化,而我们又想访问该类的成员。
static bool MyCondition1(MyTest it)
{
if (it.x == 114514) return true;
return false;
}
//该函数必定返回 false
static bool MyCondition2(MyTest it)
{
//if (it == null) return true;
return false;
}
static void Main()
{
MyTest test1 = new MyTest(114514), test2 = new MyTest(92935);
Predicate<MyTest> pTest1 = MyCondition1, pTest2 = MyCondition2;
List<MyTest> list = new List<MyTest>();
list.Add(test1);
list.Add(test2);
MyTest t1 = list.Find(pTest1);
//t2 一定为空,因为pTest2一定返回false
MyTest t2 = list.Find(pTest2);
if (t1 == null) Console.WriteLine("Fail to find object");
else Console.WriteLine(t1.x);
if (t2 == null) Console.WriteLine("Fail to find object");
else Console.WriteLine(t2.x);
}
}
上述代码中 list.Find(pTest1) 可以替换为 list.Find(MyCondition1)。 list.Find 函数接收一个委托类型的变量,如果我们填入一个与委托签名一致的函数(返回类型、参数),在这种情况下编译器会自动帮我们把函数转成对应的委托。这很重要。
结果:
更通用的写法
注意:Lambda 表达式可以被隐式的转为委托。并且委托签名一致的函数在该种情况下也可自动转为委托。
Lambda 表达式
Lambda表达式 是 C# 的语法糖,它的本质就是一个函数,我们只需要写出一些最关键的信息,剩下的编译器会帮我们自动推断出来。Lambda 表达式可以让我们不用声明委托,而直接将其作为 List.Find 的参数,剩下就是编译器的工作了
static void Main()
{
MyTest test1 = new MyTest(114514), test2 = new MyTest(92935);
//委托可以用 Lambda 表达式替代
Predicate<MyTest> pTest2 = it => it == null;
List<MyTest> list = new List<MyTest>();
//参数: (it) => {it.x == test1.x} 为什么可以这么写是委托已经指明了返回值和需要接收的类型
//我们只需指出最关键的信息:参数是 it , 返回值是 it.x == test1.x,可以这么写的前提是我们的
//函数体没有其他内容,否则就必须写 return it.x == test1.x;
MyTest t1 = list.Find(it => it.x == test1.x);
MyTest t2 = list.Find(pTest2);
//...
}
Lambda 表达式的好处是其简单,灵活,如果我们用的少的话,它可能是一个不错的选择,但如果我们经常用那不是没用一次,就要写一次 Lambda 表达式,这显然有些麻烦。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了