C#委托11111(上)

简介: C#委托11111

在C#中的委托关键字是 Delegate,委托类似于C/C++中函数的指针。是存有对某个方法引用的引用类型变量,可在运行时被改变。一般用于实现事件和回调方法。


注意:所有的委托都派生自 System.Delegate 类

委托分为 委托类型委托实例 ,下面分别进行讲解。


零、委托类型和委托实例

1. 委托类型
委托类型定义了委托实例可以调用的方法、方法的返回类型和参数。我们可以通过委托类型的返回类型和参数来得知具体可以调用哪种方法。下面我们通过一个例子来看一下:

  • 首先我们定义一个委托类型:
delegate string DemoDelegate(int num);
  • 其次我们定义两个方法:
string IntToString(int num)
{
    return num.ToString();
}
int StringToInt(string num)
{
    return int.Parse(num);
}

我们来分析一下这两个代码段。首先我们定义了一个委托 DemoDelegate ,委托所定义的返回值类型是 string 类型,参数只包含一个,参数类型是 int。因此根据委托定义得知只有方法的返回值类型是 string 且参数只有一个,并且

参数类型是 int 时,委托才能调用。所以符合条件的方法就只有 IntToString


2.委托实例


当把方法赋值给委托变量的时候就创建了委托实例。同样我们用一个例子来看一下:

static void Main(string[] args)
{
    DemoDelegate dd = IntToString;
    string num = dd(123);
    // 将输出 string 类型 "123"
    Console.WriteLine(num);
}

委托实例本质上就是调用者委托委托方法调用被调用者,在这里就是 Main 方法委托 DemoDelegate 去调用 IntToString 方法。这样做的好处是调用者和被调用者的耦合度降低了。

小知识:上面的代码我们还可以这样写,这两种写法是等价的:

static void Main(string[] args)
{
    DemoDelegate dd = new DemoDelegate(IntToString);
    string num = dd.Invoke(123);
    // 将输出 string 类型 "123"
    Console.WriteLine(num);
}

委托的用途很多,我们这里来看一个例子,这个例子展示了委托其中一种的用途

public delegate int DemoDelegate(int num);
class Tool
{
    public static void IntSquare(int[] intArray, DemoDelegate dd)
    {
        for (int i = 0; i < intArray.Length; i++)
        {
            intArray[i] = dd(intArray[i]);
        }
    }
}
class Program
{
    static void Main(string[] args)
    {
        DemoDelegate dd = Square;
        int[] intArray = {2,4,6 };
        Tool.IntSquare(intArray, dd);
        for (int i = 0; i < intArray.Length; i++)
        {
            Console.WriteLine(intArray[i]);
        }
        Console.Read();
    }
    static int Square(int num)
    {
        return num * num;
    }
}

我们将委托提取出来,作为一个公共的,然后定义一个 Tool 类,其中定义了一个计算数组中每个值的方法,这个方法接受两个参数,一个是int类型的数组,另一个是 DemoDelegate 委托类型的参数。通过委托调用 Program 类中的 Square 方法来计算数组中每个数字的平方值。我们在 Main 方法中将 Square 方法赋值给委托变量,然后见数组和委托变量一同传入刚才我们定义的 Tool 类中的 IntSquare 方法,最后输出值为:4、16、36。这种用途叫做编写插件式方法,插件式方法就是只有在运行时才将方法赋值给委托。


一、多播委托

前面的例子我们都是讲一个方法赋值给委托变量,这种叫单播委托。但是在大部分情况下我们需要将多个方法赋值给委托,这是我们就用到了多播委托。要把多个方法赋值给委托变量,我们需要用到 + += ,方法如下:

Delegate d = method1;
d += method2;

当我们调用委托 d 的时候,就会按照赋值顺序来调用方法,即先调用 method1 再调用 method2 。我们有时候也需要移除委托中的某个方法,这时我们可以用 --= 进行操作,比如我们移除前面例子中的 method1 方法:

d -= method1;

当我们进行 + 或者 += 操作时,操作数可以是null,相当于把一个新值赋值给了委托变量,也就是说如下两种方法是等价的:

方法一:

Delegate d = null;
d += method1;

方法二:

d = method1;

同理,当进行 - 或者 -= 操作时,相当于把null值赋给了委托变量。

下面我们来看一下多播委托的例子:

public delegate int DemoDelegate(int num);
static void Main(string[] args)
{
    DemoDelegate dd = null;
    dd += Square;
    dd += Remainder;
    dd(5);
    Console.Read();
}
static int Square(int num)
{
    Console.WriteLine(num * num);
    return num * num;
}
static int Remainder(int num)
{
    Console.WriteLine(num % 2);
    return num % 2;
}

在代码中我们定义了两个方法,分别是计算数值平方的 Square 和计算数值除以2的余数 Remainder 。在 Main 方法中我们利用 += 将两个方法赋值给委托变量 dd 。执行这段代码,最终输出结果为:25、1。当我们利用 - 或者 -= 来移除掉一个方法时,例如移除掉 Square ,这时就只会输出1,当我们把所有的方法都移除掉时,程序运行起来将会报空指针异常的错误。

注意:

  1. 委托不可变,使用 += 或者 -= 实际上是创建了新的委托实例,并把它付给当前的委托变量。
  2. 如果多播委托的返回类型不是void,那么调用者只能获取到最后一个被调用方法的返回值,前面方法的返回值将会被抛弃。
  3. c#会将 +、-、+=、-=编译为 Combine 和 Remove两个方法。

二、实例方法委托和静态方法委托

实例方法和静态方法都是c#中经常用到的方法,我们可以将这两种方法都赋值给委托,因此就出现了实例方法稳妥和静态方法委托。它们之间的区别如下:


  1. 一个实例方法被赋值给委托对象时,委托对象不仅要保留对方法的引用,还要保留方法所属实例的引用,这时 System.Delegate 中的 Target 属性就表示的是方法所属的实例;
  2. 一个静态方法赋值给委托对象时,Target 属性值为null。


例子如下:

  • 首先定义一个类 Demo 里边包含 NumAdd 实例方法和 Num 静态方法
class Demo
{
    public int NumAdd(int num)
    {
        return ++num;
    }
    public static int Num(int num)
    {
        return num;
    }
}


目录
相关文章
|
3月前
|
C#
C#一分钟浅谈:委托与事件的实现方式
本文详细介绍了C#编程中委托与事件的基础知识及应用场景。首先解释了委托的概念,包括定义与使用方法;接着介绍了事件这一基于委托的特殊类型,展示了如何在类中定义事件及跨类订阅与处理事件;最后讨论了常见问题如事件未处理异常、重复订阅及内存泄漏等,并提出了相应的解决方案。通过本文,读者将全面掌握委托与事件的使用技巧,提升应用程序的设计与开发水平。
145 7
|
4月前
|
编译器 C#
C#中内置的泛型委托Func与Action
C#中内置的泛型委托Func与Action
71 4
|
4月前
|
C#
C#中的委托(一)
C#中的委托(一)
41 1
|
4月前
|
C# C++
C#语言进阶(一)—委托
C#语言进阶(一)—委托
53 0
|
7月前
|
存储 安全 C#
C# - 委托与事件
这篇文档介绍了C#中的委托和事件。委托是存储方法引用的类型,支持回调、事件处理,具有引用方法、类型安全、多播性等特性,并在异步编程中发挥作用。事件是委托的封装,提供保护和订阅机制,防止外部直接访问。当需要在类内部控制方法调用,防止外部误触发时,可使用事件。
|
6月前
|
C#
C#||委托和事件的实例
C#||委托和事件的实例
|
7月前
|
C#
c#委托详解
c#委托详解
43 0
|
7月前
|
开发框架 安全 .NET
C# .NET面试系列三:集合、异常、泛型、LINQ、委托、EF!
<h2>集合、异常、泛型、LINQ、委托、EF! #### 1. IList 接口与 List 的区别是什么? IList 接口和 List 类是C#中集合的两个相关但不同的概念。下面是它们的主要区别: <b>IList 接口</b> IList 接口是C#中定义的一个泛型接口,位于 System.Collections 命名空间。它派生自 ICollection 接口,定义了一个可以通过索引访问的有序集合。 ```c# IList 接口包含一系列索引化的属性和方法,允许按索引访问、插入、移除元素等。 由于是接口,它只定义了成员的契约,而不提供具体的实现。类似于 IEnumera
367 2
|
7月前
|
存储 C# C++
C#进阶-委托(Delegrate)
类似于 C 或 C++ 中函数的指针,委托是C#的函数指针,是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。本篇文章我们将讲解C#里委托的类型及如何使用。委托的语法第一次接触难免感到陌生,最好的学习方式就是在项目中多去使用,相信会有很多感悟。
53 0