首页 > 其他分享 >.NET Core 委托原理解析

.NET Core 委托原理解析

时间:2025-01-13 17:43:19浏览次数:1  
标签:Core Console 委托 del WriteLine NET 解析 方法 public

.NET Core 委托原理解析

在 .NET Core 中,委托(Delegate)是一种类型安全的函数指针,它允许你将方法作为参数传递给其他方法,或者将方法存储在变量中以便稍后调用。委托在事件处理、回调机制以及异步编程中非常有用。理解委托的运行原理对于掌握 .NET Core 的高级编程技巧至关重要。

1. 委托的基本概念

委托是一种引用类型,它引用一个或多个方法。委托定义了方法的签名(参数类型和返回类型),因此只有具有相同签名的方法才能被委托引用。

1.1 定义委托

你可以通过 delegate 关键字来定义一个委托类型。例如:

 // 定义一个委托类型
public delegate void GreetDelegate(string name);

这个委托类型 GreetDelegate 可以引用任何具有 void 返回类型和 string 参数的方法。

1.2 实例化委托

一旦定义了委托类型,你可以创建该委托的实例,并将方法赋值给它。例如:

  // 与委托签名匹配的方法
  public void Greet(string name)
  {
      Console.WriteLine($"Hello, {name}!");
  }

  // 创建委托实例并绑定方法
  GreetDelegate del  = new GreetDelegate(Greet);

在这个例子中,del 是一个委托实例,它引用了 Greet 方法。

1.3 调用委托

你可以像调用方法一样调用委托:

// 调用委托
del("World");

这会调用 del 方法,并输出 "Hello, World!"

2.委托的类型

1. 单播委托(Singlecast Delegate)

单播委托是指一个委托实例只能引用一个方法。这是最基本的委托类型。

public delegate void GreetDelegate(string message);

public void ShowMessage(string message)
{
    Console.WriteLine(message);
}

GreetDelegate del = new GreetDelegate(ShowMessage);
del("Hello, World!"); // 输出:Hello, World!

2. 多播委托(Multicast Delegate)

多播委托是指一个委托实例可以引用多个方法。通过 += 运算符可以将多个方法添加到委托实例中,并通过 -= 运算符移除方法。

public void ShowMessage1(string message)
{
    Console.WriteLine($"Message 1: {message}");
}

public void ShowMessage2(string message)
{
    Console.WriteLine($"Message 2: {message}");
}

public void ShowMessage3(string message)
{
    Console.WriteLine($"Message 3: {message}");
}

GreetMulticastDelegate del = new GreetMulticastDelegate(ShowMessage1);
del += ShowMessage2;
del += ShowMessage3;
del -= ShowMessage2;

del("Hello, World!");

在这个例子中,del 委托实例引用了多个方法:将ShowMessage1,ShowMessage2ShowMessage3添加到了多播委托实例中,然后并通过 -= 运算符移除ShowMessage2。然后调用 del("Hello, World!") 时,三个方法都会被调用,输出如下:

Message 1: Hello, World!
//ShowMessage2方法已移除
Message 3: Hello, World!

3. 泛型委托(Generic Delegate)

泛型委托是 C# 中的一种特殊委托类型,它允许你定义可以处理多种数据类型的委托。通过使用泛型,你可以编写更通用、更灵活的代码,而不需要为每种数据类型单独定义委托。

以下是几个泛型委托的示例,展示了如何使用泛型委托处理不同类型的数据。

3.1 简单的泛型委托

public delegate T MyGenericDelegate<T>(T arg);

public int Square(int x)
{
    return x * x;
}

public string Reverse(string s)
{
    return new string(s.Reverse().ToArray());
}

MyGenericDelegate<int> intDelegate = new MyGenericDelegate<int>(Square);
Console.WriteLine(intDelegate(5)); // 输出:25

MyGenericDelegate<string> stringDelegate = new MyGenericDelegate<string>(Reverse);
Console.WriteLine(stringDelegate("hello")); // 输出:olleh
  • 说明
    • MyGenericDelegate 实例化了一个处理 int 类型数据的委托。
    • MyGenericDelegate 实例化了一个处理 string 类型数据的委托。

3.2 多参数泛型委托

public delegate TResult MyGenericDelegate<T1, T2, TResult>(T1 arg1, T2 arg2);

public int Add(int a, int b)
{
    return a + b;
}

public string Concat(string s1, string s2)
{
    return s1 + s2;
}

MyGenericDelegate<int, int, int> intDelegate = new MyGenericDelegate<int, int, int>(Add);
Console.WriteLine(intDelegate(3, 5)); // 输出:8

MyGenericDelegate<string, string, string> stringDelegate = new MyGenericDelegate<string, string, string>(Concat);
Console.WriteLine(stringDelegate("Hello, ", "World!")); // 输出:Hello, World!
  • 说明
    • MyGenericDelegate 实例化了一个处理两个 int 类型参数并返回 int 类型结果的委托。
    • MyGenericDelegate 实例化了一个处理两个 string 类型参数并返回 string 类型结果的委托。

4. 内置委托类型

C# 提供了一些内置的泛型委托类型,可以直接使用,而无需自定义委托。

4.1 Action 委托

Action 委托用于引用没有返回值的方法。它可以有 0 到 16 个参数。

Action<string> action = (message) => Console.WriteLine(message);
action("Hello, World!"); // 输出:Hello, World!

4.2 Func 委托

Func 委托用于引用有返回值的方法。它可以有 0 到 16 个参数,最后一个泛型参数是返回值类型。

Func<int, int, int> add = (a, b) => a + b;
Console.WriteLine(add(3, 5)); // 输出:8

4.3 Predicate 委托

Predicate 委托用于引用返回布尔值的方法,通常用于条件判断。

Predicate<int> isEven = (num) => num % 2 == 0;
Console.WriteLine(isEven(4)); // 输出:True

5. 匿名方法委托

匿名方法允许你直接定义委托的实现,而无需显式声明一个方法。

MyDelegate del = delegate(string message)
{
    Console.WriteLine(message);
};

del("Hello, World!"); // 输出:Hello, World!

6. Lambda 表达式委托

Lambda 表达式是一种更简洁的匿名方法写法,通常用于定义委托。

Action<string> action = (message) => Console.WriteLine(message);
action("Hello, World!"); // 输出:Hello, World!

Func<int, int, int> add = (a, b) => a + b;
Console.WriteLine(add(3, 5)); // 输出:8

7. 事件委托

事件是一种特殊的委托,通常用于实现观察者模式。事件委托通常与 EventHandlerEventHandler 一起使用。

public class Button
{
    public event EventHandler Click;

    public void OnClick()
    {
        Click?.Invoke(this, EventArgs.Empty);
    }
}

public class Program
{
    public static void Main()
    {
        Button button = new Button();
        button.Click += (sender, e) => Console.WriteLine("Button clicked!");
        button.OnClick(); // 输出:Button clicked!
    }
}

8. 异步委托

异步委托允许你异步调用方法,通常与 BeginInvokeEndInvoke 一起使用。

public delegate int MyAsyncDelegate(int x, int y);

public int Add(int a, int b)
{
    return a + b;
}

MyAsyncDelegate del = new MyAsyncDelegate(Add);
IAsyncResult result = del.BeginInvoke(3, 5, null, null);
int sum = del.EndInvoke(result);
Console.WriteLine(sum); // 输出:8

9. 动态委托

动态委托允许你在运行时动态创建和调用委托。

public int Multiply(int a, int b)
{
    return a * b;
}

var method = typeof(Program).GetMethod("Multiply");
var del = Delegate.CreateDelegate(typeof(Func<int, int, int>), null, method);
int result = (del as Func<int, int, int>)(3, 5);
Console.WriteLine(result); // 输出:15

3. 委托的运行原理

委托的运行原理涉及到 .NET Core 的运行时机制和内部实现。以下是委托运行原理的关键点:

3.1 委托的内部结构

在 .NET Core 中,委托是一个类,它继承自 System.MulticastDelegate 类。System.MulticastDelegate 类又继承自 System.Delegate 类。委托类包含以下关键成员:

  • _target:指向调用方法的对象实例(如果是静态方法,则为 null)。
  • _methodPtr:指向方法的函数指针。
  • _invocationList:用于存储多播委托中的多个方法。

3.2 委托的调用

当你调用委托时,.NET Core 运行时会执行以下步骤:

  1. 1. 检查委托实例是否为**** **null**:如果委托实例为 null,则会抛出 NullReferenceException
  2. 2. 调用委托的**** **Invoke** ****方法:委托实例的 Invoke 方法会被调用,该方法会根据 _target_methodPtr 调用实际的方法。
  3. 3. 处理多播委托:如果委托是多播委托(即 _invocationList 不为 null),则 Invoke 方法会遍历 _invocationList,依次调用每个方法。

3.3 委托的优化

.NET Core 对委托的调用进行了优化,以提高性能。例如,对于单播委托(即只引用一个方法的委托),.NET Core 会直接调用方法,而不需要通过 Invoke 方法。

4. 委托的应用场景

委托在 .NET Core 中有多种应用场景,以下是一些常见的场景:

4.1 事件处理

委托在事件处理中非常常见。事件是一种特殊的委托,它允许对象在发生某些事情时通知其他对象。例如:

C#public class Button
{
    public event Action Click;

    public void OnClick()
    {
        Click?.Invoke();
    }
}

public class Program
{
    public static void Main()
    {
        Button button = new Button();
        button.Click += () => Console.WriteLine("Button clicked!");
        button.OnClick();
    }
}

在这个例子中,Button 类定义了一个 Click 事件,当 OnClick 方法被调用时,事件处理程序会被触发。

4.2 回调机制

委托可以用于实现回调机制,允许一个方法在完成时通知另一个方法。例如:

public void DoWork(Action callback)
{
    // 执行一些工作
    Console.WriteLine("Work is done.");

    // 调用回调方法
    callback?.Invoke();
}

public void Main()
{
    DoWork(() => Console.WriteLine("Callback called."));
}

在这个例子中,DoWork 方法在完成工作后调用传入的回调方法。

4.3 异步编程

委托在异步编程中也非常有用。例如,Task 类的 ContinueWith 方法允许你在任务完成时执行一个委托:

Task.Run(() => Console.WriteLine("Task is running..."))
    .ContinueWith(task => Console.WriteLine("Task is completed."));

5. 总结

委托是 .NET Core 中一个非常强大的特性,它允许你将方法作为参数传递、存储和调用。理解委托的运行原理有助于你更好地利用这一特性,特别是在事件处理、回调机制和异步编程中。通过掌握委托,你可以编写更加灵活和可扩展的代码。

标签:Core,Console,委托,del,WriteLine,NET,解析,方法,public
From: https://www.cnblogs.com/liyongqiang-cc/p/18636233

相关文章

  • websocket-sharp:.NET平台上的WebSocket客户端与服务器开源库
    推荐一个C#开发的,实现WebSocket功能的开源项目。01项目简介websocket-sharp提供WebSocket客户端和服务器库,基于C#开发的,并遵循WebSocket协议规范,使得开发人员能够轻松地在.NET应用程序中实现WebSocket通信。websocket-sharp特色功能有:1、简洁易用的API:提供清晰且......
  • 【Python】深入解析Python的上下文管理器与资源管理:实现自定义的`with`语句
    《PythonOpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门!解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界在现代编程中,资源管理的高效与安全性至关重要。Python通过上下文管理器与with语句为开发者提供了一种简洁而强大的资源管理机制。上下文管理器......
  • 大模型应用场景落地:实操项目全解析
    你是否学习了大模型技术,但是不知道如何落地?今天带来5个大模型落地项目,保证你看完一定有所收获!前排提示,文末有大模型AGI-CSDN独家资料包哦!大模型应用#1:从Chatbot到AIAgent,个人助理重塑手机应用生态AI大模型的能力进步推动Chatbot在C端广泛“出圈”。Chatbot(聊天机器人)通......
  • 基于YOLOv8与CGNet的鸟类智能识别系统 深度学习图像分类 鸟类目标检测与分类 图像特征
    博主介绍:  ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W+粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台的优质作者。通过长期分享和实战指导,我致力于帮助更多学生......
  • .NET Core GC标记阶段(mark_phase)底层原理浅谈
    简介C#采用基于代的回收机制,并使用了更复杂的链式跟踪算法来识别对象是否为垃圾。GC触发的原因截至到.NET8,GC触发的原因有18种enumgc_reason{reason_alloc_soh=0,//小对象堆,快速分配预算不足reason_induced=1,//主动触发GC,没有关于压缩和阻塞的选项r......
  • 求解整数二进制中1的个数:func(9999)实现解析
    @TOC问题描述给定一个函数func(x),其目的是计算整数x的二进制表示中1的个数。函数的实现通过不断清除x的最低位的1,直到x变为0,并计数执行了多少次这样的操作。假设x=9999,我们需要找出func(9999)的返回值。思路二进制转换:将x转换为二进制数。计数1......
  • RabbitMQ 高可用方案:原理、构建与运维全解析
    文章目录前言:1集群方案的原理2RabbitMQ高可用集群相关概念2.1设计集群的目的2.2集群配置方式2.3节点类型3集群架构3.1为什么使用集群3.2集群的特点3.3集群异常处理3.4普通集群模式3.5镜像集群模式前言:在实际生产中,RabbitMQ常以集群方案部署。因选用它......
  • .NET 开发的分流抢票软件,不做广告、不收集隐私
    前言每年春节大家必备的抢票工具Bypass-分流抢票。分流抢票是一款免费无广适用于PC端的自动分流抢票软件。分流抢票,是以用户为中心、人性化的抢票软件。不做广告、不做推广、不携带病毒、不收集隐私信息,并接受各方技术评测,全心全意为用户打造一款属于自己的抢票软件。项目介绍......
  • 软考~系统规划与管理师考试——真题篇——2020年11月——综合知识——解析版
    文章目录真题(2020-11-01)真题(2020-11-02)真题(2020-11-03)真题(2020-11-04)真题(2020-11-05)真题(2020-11-06)真题(2020-11-07)真题(2020-11-08)真题(2020-11-09)真题(2020-11-10)真题(2020-11-11)真题(2020-11-12)真题(2020-11-13)真题(2020-11-14)真题(2020-11-15)真题(2020-11-16)真题(2020-11-17)真题......
  • Qt多线程开发全解析
     目录一、引言二、Qt多线程基础概念2.1线程与进程2.2Qt中的线程类三、Qt多线程的使用场景3.1耗时操作处理3.2实时数据处理3.3多任务并发执行四、Qt多线程的实现方式4.1继承QThread类4.2使用QThreadPool线程池4.3利用QtConcurrent框架五、线程间的同步......