C#自学笔记:匿名函数与Lambda表达式

匿名函数

没有名字的函数

匿名函数的使用主要是配合委托和事件进行使用

脱离委托和事件,是不会使用匿名函数的

基本语法

delegate (参数列表)
{
    //函数逻辑
};

何时使用?

  1. 函数中传递委托参数时
  2. 委托或事件赋值时

使用

相当于直接声明了一个没有名字的函数,然后直接放进委托的容器中存起来
//1. 无参无返回值
Action a = delegate()
{
    Console.WriteLine("匿名函数逻辑");
};
a();

//2. 有参
Action<int, string> b = delegate (int a, string b)
{
    Console.WriteLine(a);
    Console.WriteLine(b);
};
b(100, "123");

//3. 有返回值
Func<string> c = delegate()
{
    return "123123";
};
Console.WriteLine(c());

//4. 一般情况下会作为函数参数传递或者作为函数返回值
Test t = new Test();
//参数传递
t.Dosomthing(100, delegate()
{
    Console.WriteLine("匿名函数逻辑");
});
//返回值
Action ac = t.GetFun();
ac();
//一步到位,直接调用返回的委托函数
t.GetFun()();

class Test
{
    public void Dosomthing(int a, Action fun)
    {
        Console.WriteLine(a);
        fun();
    }

    //作为返回值
    public Action GetFun()
    {
        return delegate() 
        {

        };
    }
}

缺点

添加到委托或事件容器中后不记录,无法单独移除
  • 因为匿名函数没有名字,所以没有办法指定移除某一个匿名函数
  • 就算写的逻辑一模一样也是没有用的,相当于两个函数了

要移除只能通过把整个委托或事件容器清空

ac = null;

lambad表达式

可以理解为匿名函数的简写

除了写法不一样,使用上一模一样

都是和委托或者事件配合使用的

语法

//匿名函数
delegate (参数列表)
{
};

//lambad表达式
(参数列表) =>
{
};

使用

//1. 无参无返回值
Action a = () =>
{
    //逻辑
};

//2. 有参无返回值
Action<int> a2 = (int value) =>
{
    Console.WriteLine(value);
};

//3. 甚至参数类型都可以省略
Action<int> a3 = (value) =>
{
    Console.WriteLine(value);
};

//4. 有参有返回值
Func<string, int> a4 = (value) =>
{
    Console.WriteLine(value);
    return 1;
};
Console.WriteLine(a4("123123"));

缺点也和匿名函数一样

闭包

内层的函数可以引用包含在它外层的函数的变量

即使外层函数的执行已经终止

注意:该变量提供的值并非变量创建时的值,而是在父函数范围内的最终值。

class Test
{
    public event Action action;
    public Test()
    {
        int value = 10;
        //这里就形成了闭包
        action = () =>
        {
            Console.WriteLine(value);
        };

        //注意
        for (int i = 0; i < 10; i++)
        {
            action += () =>
            {
                Console.WriteLine(i);//调用action时打印出来的全是10
            };
            
            int index = i;
            action += () =>
            {
                Console.WriteLine(index);//这里打印出来就是0-9
            };
        }
    }
}

理应上 Test 函数运行完 value 要被回收,由于在 action 中存进了一个匿名函数,value 就不会被回收,只有在 action 置空才会被回收

存进去的是变量的地址而不是值,所以在调用时会找到该地址,获取变量的最终值。

List排序

List自带排序方法

List<int> list = new List<int>();
list.Add(2);
list.Add(5);
//默认是升序排序
list.Sort();

int泛型可以自动排序是因为系统帮我们写好了排序的方法

自定义类的排序

如果是自定义类想要使用list自带的排序方法时,需要继承一个排序接口,实现一个排序的规则
class Item : IComparable<Item>
{
    public int money;

    public Item(int money)
    {
        this.money = money;

    }

    public int CompareTo(Item other)
    {
        //返回值的含义
        //小于0:当前对象放在传入对象的前面
        //等于0:保持当前的位置不变
        //大于0:当前对象放在传入对象的后面

        //可以简单理解为传入对象的位置就是0
        //如果返回值为负数,我就放在它的左边
        //如果返回值为正数,我就放在它的右边
        if (this.money > other.money)
        {
            return 1;
        }
        else 
        {
            return -1;
        }
    }
}

List<Item> items = new List<Item>();
items.Sort();

通过委托函数进行排序

List.Sort()底层
public void Sort();

public void Sort(Comparison<T> comparison);

public delegate int Comparison<in T>(T x, T y);

Comparison是个委托,可以传入函数进行排序

使用

List<ShopItem> shopItems = new List<ShopItem>();
shopItems.Add(new ShopItem(2));
shopItems.Add(new ShopItem(1));

shopItems.Sort(SortShopItem);

static int SortShopItem(ShopItem a, ShopItem b)
{
    if (a.id > b.id)
    {
        return 1;
    }
    else 
    { 
        return -1;
    }
}

//简化:用匿名函数 -> 省去delegate声明和参数类型 -> lambad表达式 -> 三目运算符
shopItems.Sort((a, b) => 
{
    return a.id > b.id ? 1 : -1;
};

个人用的最多的是第三种方式

posted @ 2025-08-08 18:41  柠凉w  阅读(63)  评论(0)    收藏  举报