委托和事件

C#语言中委托(delegate)可以实现类似C/C++的函数指针的作用,而事件(event)实现了发布订阅设计模式,可以用于实现对特定动作进行一系列响应。在日常开发中,两者还经常结合使用,例如Winform中就使用了委托和事件,实现为控件注册回调函数的机制。

delegate 委托

如果熟悉C/C++我们应该了解函数指针,C#语言中没有函数指针,但给出了委托(delegate)的概念。委托可以看作一种安全的函数指针对象,它是一个引用类型,能够将函数的调用包装为变量。此外,委托比函数指针更加灵活,委托不仅可以包装一个函数,还可以包装一组函数实现组合委托。下面代码实现了一个简单的回调函数机制。

delegate void Callback();

class Program
{
    static void Main()
    {
        void foo()
        {
            Console.WriteLine("程序运行成功!");
        }
        Callback cb = new Callback(foo);

        loadData(cb);
    }

    static void loadData(Callback cb)
    {
        Console.WriteLine("加载数据中...");
        cb();
    }
}

上面例子代码中,我们首先声明了一个委托类型Callback。委托的声明使用delegate关键字,后面部分则和函数声明非常类似,实际上它规定了委托可以关联的函数签名。在Main函数中,我们首先定义了一个局部函数foo,然后创建委托对象cb,并将局部函数的函数名作为参数传入其中。最终,我们将委托对象传入了另一个方法中,此时可以直接使用类似调用函数的方式调用委托对象cb,函数foo会被触发执行。

创建委托

上面代码我们使用了一个局部函数创建委托,实际上实例方法、静态方法都可以用来创建委托。

// 使用实例方法创建委托
Callback c1 = new Callback(demoClass.Foo);
// 使用静态方法创建委托
Callback c2 = new Callback(DemoClass.Bar);

更进一步,其实new Callback()也可以省略掉,简化的语法如下。

// 使用实例方法创建委托
Callback c1 = demoClass.Foo;
// 使用静态方法创建委托
Callback c2 = DemoClass.Bar;

组合委托

实际上委托不仅能包含一个函数调用,也可以包含多个,这被称为组合委托。两个委托类型可以使用+运算符生成一个新的组合委托。

Callback c1 = DemoClass.Foo;
Callback c2 = DemoClass.Bar;

Callback c3 = c1 + c2;

调用组合委托c3时,会依次调用c1c2

委托也支持+=-=运算符。

Callback c1 = DemoClass.Foo;
c1 += DemoClass.Bar;
c1 -= DemoClass.Foo;

这里要注意,委托类似于string,是一个不可变对象,然而C#又为委托提供了+=-=运算符,大家不要感到迷惑,实际上这里是生成了新的委托对象,而非在原来的委托对象上修改。

匿名方法

初始化委托时我们需要传入一个函数,然而如果这个函数仅用于初始化委托,单独定义一个函数的写法就比较麻烦了。C#2.0引入了匿名函数语法,用于简化这类代码的编写。

Callback c = delegate ()
{
    Console.WriteLine("hello");
};

上面代码中,Callback是一个委托类型,我们直接使用了一个匿名方法对其进行了初始化。匿名方法也是使用delegate关键字修饰,且不需要设定方法名(毕竟这个概念就叫做匿名方法),小括号内可以指定方法的参数,匿名方法声明中不需要指定返回值,但如果委托具有非void的返回值,匿名方法的方法体必须返回相同类型的数据。

匿名方法的另一个特性是它可以访问其外部作用域内的变量,比如下面代码中,匿名方法体内就可以访问外部的变量x

int x = 1;

Callback c = delegate ()
{
    Console.WriteLine("x={0}", x);
};

lambda表达式

实际上匿名方法的编写还是有一些麻烦,C#3.0引入了lambda表达式,能够进一步简化匿名方法的写法。实际开发中,绝大多数都是使用lambda表达式,而非匿名方法的写法。

Callback c = () =>
{
    Console.WriteLine("hello");
};

lambda表达式使用() => { }写法指定,用法和匿名方法一致。

event 事件

C#中事件可以实现发布订阅设计模式,简单来说就是注册一些回调函数,满足特定条件时回调函数执行,事件需要结合委托来实现。下面例子代码实现了事件的声明和使用。

delegate void Callback();

class Demo
{
    public event Callback callback;

    public void foo()
    {
        callback();
    }
}

class Program
{
    static void Main()
    {
        Demo demo = new Demo();
        demo.callback += () =>
        {
            Console.WriteLine("hello");
        };
        demo.foo();
    }
}

代码中,我们首先声明了一个委托Callback,类Demo中我们使用event关键字声明了一个事件,注意声明事件时需要使用委托类型,对应类型的委托会注册到事件中。最后在Main方法中,我们实例化了这个类,并使用+=运算符为事件注册回调函数。调用foo方法后,回调函数被执行。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap