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 表达式,这显然有些麻烦。


 
 
posted @   yinghualeihenmei  阅读(137)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示