当前位置: 首页 > news >正文

C#泛型委托

在C#中,delegate 关键字用于声明委托(delegates),委托是一种类型安全的函数指针,允许你传递方法作为参数或从方法返回方法。有时我们需要将一个函数作为另一个函数的参数,这时就要用到委托(Delegate)机 制。

delegate void GDelegate<T>(T t);
定义了一个名为 GDelegate 的泛型委托。这个委托接受一个类型为 T 的参数 t,并且不返回任何值(void)。T 是一个类型参数,意味着这个委托可以用于任何类型的方法,只要那个方法有一个参数并且没有返回值。

在C#中,Action 是一个内置的委托(delegate)类型,用于封装没有返回值(即返回类型为 void)的方法。Action 委托有多个重载版本,可以接受不同数量的参数,每个参数可以有不同的类型。
Action 委托的基本定义如下:
public delegate void Action(); // 没有参数  
public delegate void Action<T>(T obj); // 一个参数  
public delegate void Action<T1, T2>(T1 arg1, T2 arg2); // 两个参数  
// ... 以此类推,直到 Action<T1, T2, ..., T16>

在C#中,Func<TResult> 是一个泛型委托,用于封装具有返回值的方法。与 Action 委托不同,Func 委托总是有一个返回值,并且可以接受任意数量的输入参数。在你给出的例子中,Func<String, String> 是一个特定的 Func 委托类型,它接受一个 string 类型的参数并返回一个 string 类型的值。

Func<String,String>func=new Func<String,String>(Method3);
func("我是带返回值的Func委托"); 

Gdelegate类: 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace 泛型委托
{delegate void GDelegate<T>(T t);//定义了一个名为 Gdelegate 的泛型委托。这个委托接受一个类型为 T 的参数 t,并且不返回任何值//T 是一个类型参数,意味着这个委托可以用于任何类型的方法,只要那个方法有一个参数并且没有返回值。internal class Gdelegate//internal 是一个访问修饰符,用于指定一个类型或成员仅在其声明它的程序集中可见{static string result;public static void InvokeDelegate() {GDelegate<string> gdelegate1 = new GDelegate<string>(Method1);//把方法以变量的形式传送,并以方法的形式执行gdelegate1("我是泛型委托1");Action<String>action=new Action<String>(Method1);action("我是泛型委托1-action");//官方版本(不带返回值),效果同
//Action<T>和Func<TResult>这两个内置的委托类型,它们分别在System命名空间中定义,用于处理没有返回值(Action)和带有返回值(Func)的方法。GDelegate<int> gdelegate2= new GDelegate<int>(Method2);gdelegate2(99);//传参intFunc<String,String>func=new Func<String,String>(Method3);result =func("我是带返回值的Func委托");//Func<String, String> 是一个特定的 Func 委托类型,它接受一个 string 类型的参数并返回一个 string 类型的值。}public static void Method1(string str) {Console.WriteLine(str);}public static void Method2(int num){Console.WriteLine("我是泛型委托2:"+num);}public static String Method3(string str){Console.WriteLine(result + "AB");return str+"A";}}
}

  Program类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace 泛型委托
{internal class Program{static void Main(string[] args){Gdelegate.InvokeDelegate();//调用静态方法----类名.方法名string str= Gdelegate.Method3("我是带参的");//str接收的是return str+"A"// Func 委托类型,它接受一个 string--"我是带参的" 类型的参数,并返回一个 stringConsole.WriteLine(str);Console.ReadKey();}}}

启动程序:

AB是在执行:Gdelegate.InvokeDelegate();//调用静态方法----类名.方法名
时执行了: Func<String,String>func=new Func<String,String>(Method3);--->Console.WriteLine(result + "AB");//
而result 此时为null.下一句:result =func("我是带返回值的Func委托:");
 result接收了:"我是带返回值的Func委托:"+"A"
所以才有了执行:string str= Gdelegate.Method3("我是带参的");
时的:我是带返回值的Func委托:AAB
 执行:Console.WriteLine(str);
       我是带参的A

--------------------------------------------

下面我们设计一个马戏表演函数 CircusStart(),它的第一个参数是代表动物表演的函 数,传给它什么样的函数,就进行什么动物的表演。

c#控制台程序:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace delegateAnimalPlay
{internal class Program{//定义委托 delegate void AnimalPlay(string name);//委托声明 AnimalPlaystatic void Main(string[] args){AnimalPlay deleDogPlay = new AnimalPlay(DogPlay); //把函数 DogPlay()转换为 AnimalPlay 型委托CircusStart(deleDogPlay, "Good evening");// 把委托 deleDogPlay 传给函数CircusStart()Console.ReadKey();}static void CircusStart(AnimalPlay animalPlay, string hello)//静态方法 CircusStart 的签名,该方法接受一个 AnimalPlay 委托和一个字符串参数 name{Console.WriteLine("女士们,先生们,我们的马戏表演开始了!");animalPlay(hello);}//函数:狗表演 static void DogPlay(string greetings){Console.WriteLine("{0},I am Snoopy!", greetings);//greetings接收hello--"Good evening,I am Snoopy!"Console.WriteLine(@"  狗在表演_");}//函数:猫表演 static void CatPlay(string greetings){Console.WriteLine("{0},I am Kitty!", greetings);Console.WriteLine(@" 猫在表演");}//函数:狮子表演 static void LionPlay(string greetings){Console.WriteLine("{0},I am Simba!", greetings);Console.WriteLine(@"狮子在表演 ");}  
}
}

启动程序: 

委托实例deleDogPlay实际上相当于函数DogPlay()的别名。 我们也可以传入CatPlay(),看看结果

在我们的程序中,我们总是调用函数 CircusStart()进行表演,定义该函数时,我们不 知道也不关心传递给它的委托到底代表哪个函数,直到调用函数 CircusStart(),并把实际 参数传递给它时,这个函数才具体化。传给它什么样的具体函数,就进行什么样的表演, 传给它 deleDogPlay,马戏团就进行狗的表演;传给它 deleCatPlay,马戏团就进行猫的表 演;传给它 deleLionPlay,马戏团就进行狮子表演。因此以委托为参数的函数具有一定的 通用性。 

------------------------------------

下面我们利用委托的通用性设计一个通用的求定积分的函数。

函数f(x)在区间[a,b]上定积分  \int_{a}^{b}  f x ( ) 等于函数图像与x轴所围成的曲边梯形的面积。

怎样求曲边梯形的面积呢?我们把曲边梯形分成无数块细小的矩形,这些小矩形面积 之和即可以看做曲边梯形面积的近似值。显然小矩形分得越细,面积就越精确。假如我们 把它分成1000份,则每个小矩形的宽度为:\Delta = \frac{b-a}{1000}

第i个小矩形的宽为Δ,高为f(a+iΔ),所以其面积为:Si=Δ*f(a+iΔ)

故函数f(x)在区间[a,b]上的定积分(曲边梯形的面积)为:\int_{a}^{b}  f x ( )=\sum_{i=1}^{1000}Si=\sum_{i=1}^{1000}Δ*f(a+iΔ)

求定积分,需要知道积分上限a,积分下限b和被积函数f(x),需要把被积函数以参数的形式传递给定积分函数,所以需要利用委托实现。 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace delegateIntegral
{internal class Program{ //被积函数的委托 delegate double Integrand(double x);static void Main(string[] args)//进行定积分运算{double result1 = DefiniteIntegrate(1, 5, F1);double result2 = DefiniteIntegrate(0, 1, F2);Integrand f3 = delegate (double x){return 3 * x + 5;};double result3 = DefiniteIntegrate(2, 8, f3);//匿名函数当作函数的参数Console.WriteLine("result3 = {0}", result3);Console.WriteLine("result1 = {0}", result1);Console.WriteLine("result2 = {0}", result2);Console.ReadKey();}//被积函数F1(x)=2x+1 static double F1(double x){return 2 * x + 1;}//被积函数F2(x)=x2 static double F2(double x){return x * x;}//函数:定积分 static double DefiniteIntegrate(double a, double b, Integrand fun){const int sect = 1000;//分割数目 double delta = (b - a) / sect;double area = 0;for (int i = 1; i <= 1000; i++){area += delta * fun(a + i * delta);}return area;}}
}

运行程序:

利用委托可以实现以函数为参数,提高 程序的通用性。实际上委托也是由类实现的,当我们创建一种委托时,.NET会创建一个从System.Delegate派生出来的类,类中有一个调用列表, 列表中包含着指向被委托函数的引用。学过C++的读者会觉得委托与C++的函数指针非常 类似,然而与C++的函数指针相比,委托是一种类型安全的方式,并能实现很多其它功能。

创建委托实例时不仅可以使用已有的函数,而且可以直接使用匿名函数(Anonymous Function)。

static void Main(string[] args) 

    / / 匿名函数 
    Integrand f3 = delegate(double x) 
    { 
        return 3 * x + 5; 
    } ; 
    double result3= DefiniteIntegrate(2, 8, f3); 
    Console.WriteLine("result3 = {0}", result3); 

}

也可以直接把匿名函数当作函数的参数。 double result3 = DefiniteIntegrate(2,8, delegate(double x){ return 3*x+5;});

利用匿名函数可以直接把“代码块”定义成委托,而不需要事先定义函数。在上面的 代码中我们定义了一个Integrand型委托f3,该委托的具体代码在后面的花括号中(注意, 花括号后要添加分号)。匿名函数有很多优点,比较突出的一个是它不光可以使用代码块 内定义的变量,而且可以使用代码块外定义的变量,即可以使用宿主函数的局部变量。比如下面的代码: 
static void Main(string[] args) 

double a = 3; 
double b = 5; 
    Integrand f4 = delegate(double x) 
    { 
        return a * x + b; 
    } ; 
double result4 = DefiniteIntegrate(2, 8, f4); 
    Console.WriteLine("result4 = {0}", result4);
}

在上面的代码中,在匿名函数内部使用了外部定义的变量a、b,我们把这种情况称为 外层变量被匿名函数捕获,它们的生存周期将延长至委托被销毁为止。

相关文章:

C#泛型委托

在C#中&#xff0c;delegate 关键字用于声明委托&#xff08;delegates&#xff09;&#xff0c;委托是一种类型安全的函数指针&#xff0c;允许你传递方法作为参数或从方法返回方法。有时我们需要将一个函数作为另一个函数的参数&#xff0c;这时就要用到委托&#xff08;Dele…...

从零开始精通RTSP之多播传输

概述 多播&#xff08;Multicast&#xff09;是一种高效的网络通信技术&#xff0c;它允许一台或多台主机&#xff08;可称为多播源&#xff09;发送单一数据包到多个目标主机&#xff08;可称为多播组的成员&#xff09;&#xff0c;而只有属于该多播组的接收者才会接收到这些…...

(五)STM32F407 cubemx IIC驱动OLED(2)硬件篇

这篇文章主要是个人的学习经验&#xff0c;想分享出来供大家提供思路&#xff0c;如果其中有不足之处请批评指正哈。   废话不多说直接开始主题&#xff0c;本人是基于STM32F407VET6芯片&#xff0c;但是意在你看懂这篇文章后&#xff0c;不管是F1,F4,H7等一系列系统硬件IIC配…...

头歌实践教学平台:CG1-v1.0-点和直线的绘制

第5关&#xff1a;0<k<1直线绘制-中点算法 一.任务描述 根据下面要求&#xff0c;在右侧修改代码&#xff0c;绘制出预期输出的图片。平台会对你编写的代码进行测试。 1.本关任务 掌握一种基本图形元素光栅化算法&#xff0c;利用OpenGL实现直线光栅化的中点画线算法…...

java基础之面向对象的思想

一、面向对象和面向过程的编程思想对比 面向过程&#xff1a;是一种以过程为中心的编程思想&#xff0c;实现功能的每一步&#xff0c;都是自己实现的&#xff08;自己干活&#xff09;。 面向对象&#xff1a;是一种以对象为中心的编程思想&#xff0c;通过指挥对象实现具体的…...

红黑树的理解和简单实现

目录 1. 红黑树的概念和性质 2. 红黑树的插入 2.1. 情况一&#xff1a;新增节点的父亲为空 2.2. 情况二&#xff1a;新增节点的父亲非空且为黑色节点 2.3. 情况三&#xff1a;当父亲为红节点&#xff0c;叔叔存在且为红 2.3.1. 当祖父为根节点的时候 2.3.2. 当祖父不是根…...

发表博客之:gemm/threadblock/threadblock_swizzle.h 文件夹讲解,cutlass深入讲解

文章目录 [发表博客之&#xff1a;gemm/threadblock/threadblock_swizzle.h 文件夹讲解&#xff0c;cutlass深入讲解](https://cyj666.blog.csdn.net/article/details/138514145)先来看一下最简单的struct GemmIdentityThreadblockSwizzle结构体 发表博客之&#xff1a;gemm/th…...

【C语言项目】贪吃蛇(下)

个人主页~ 源码在Gitee仓库~ 上一篇贪吃蛇&#xff08;上&#xff09;~ 贪吃蛇 四、核心的实现游戏测试1、GameStart&#xff08;1&#xff09;控制台窗口大小和名字设置&#xff08;2&#xff09;光标隐藏&#xff08;3&#xff09;打印欢迎界面&#xff08;4&#xff09;创建…...

【Unity实战|热更】Addressable读取SO文件报错解决

情景再现 假定你有一个Unity工程&#xff0c;使用了HybridCLR和Addressable&#xff0c;SO文件存放在Addressable中。热更加载后进入游戏场景出现了SO文件读取报错&#xff1a; UnityEngine.AddressableAssets.InvalidKeyException: Exception of type UnityEngine.Addressab…...

Web自动化 - selenium

文章目录 一、selenium的使用selenium的安装 二、元素1. 定位选择元素1.id 定位2. class_name 定位find_element 和 find_elements的区别3. TAG_NAME 定位4. 超链接 定位 2. 操控元素1. 查询内容2. 获取元素文本内容3. 获取元素属性 3. 浏览器常用操作API4. 鼠标操作 - perform…...

基于select for update 实现数据库分布式锁

1、select for update 的基本语法 SELECT * FROM table_name WHERE condition FOR UPDATE;2、select for update 的定义及作用 2.1 、select for update的含义是在查询数据的同时对所选的数据行进行锁定&#xff0c;以保证数据的一致性和并发控制。在并发环境下&#xff0c;多…...

Java后端实现对象与文件接收数据(minio测试)

实现思路&#xff1a; 1. 两个接口实现&#xff0c;一个接对象数据(file)&#xff0c;一个接文件数据(json)。 2. json对象(base64String) 实体类信息 &#xff0c;请求体统一接收 3. file, String name ,String password ,String name &#xff0c; Controller层接收 统一…...

考研踩坑经验分享

文章目录 写在前面自身情况简介自身学习路线优点坑点 学习路线建议1、2和3月份3、4和5月份6、7和8月份9、10月份11、12月份 一些私货建议结尾 写在前面 考研是一件非常有盼头的事&#xff0c;但绝对不是一件容易的事。 如果你不能做好来年三月份出成绩时&#xff0c;坦然接受…...

Android Compose 一:基础控件

Flutter 与 Compose 组件辣么像&#xff0c;难道是同一个google团队整的&#xff1b;也未深究&#xff0c;只是猜测。 创建项目 需要使用新版本Android studio&#xff0c;忽略步骤… 项目目录 MainActivity说明 1 系统默认页面 Preview 修饰的方法&#xff0c;只用来供开发…...

python3.12.0 在Linux 制作镜像包 部署到docker 全过程

项目结构&#xff1a; 比如&#xff0c;在pycharm里需要运行 themain.py 1、上传Linux的目录结构&#xff1a; Dockerfile 文件需要制作&#xff1a; 这里是关键&#xff1a; #基于的基础镜像 FROM python:3.12.0 #代码添加到code文件夹 ADD ./EF_NFCS /code #设置code文…...

STM32理论 —— μCOS-Ⅲ(新)

文章目录 1. 任务调度器1.1 抢占式调度 μCos-Ⅲ全称是Micro C OS Ⅲ&#xff0c;由Micriμm 公司发布的一个基于C 语言编写的第三代小型实时操作系统(RTOS)&#xff1b; RTOS 与裸机相比最大的优势在于多任务管理与实时性&#xff0c;它提供了多任务管理和任务间通信的功能&a…...

衢州知识付费系统报价,教师如何做精品课程?怎么创造精品课程?

精品课程对于学生的意义来说是不同的&#xff0c;越是精品让学习的人就越觉得值得&#xff0c;所以&#xff0c;做为教师来说&#xff0c;做出精品课程不仅仅是对学生负责&#xff0c;也是对自己负责&#xff0c;那如何做精品课程?相信很多教师们也想知道。 如何创造精品课程?…...

在Vue中,可以通过使用<slot>元素和name属性来创建具名插槽。这样您就可以为一个组件的不同部分定义不同的内容。 以下是一个简单的示例:

在Vue中&#xff0c;可以通过使用元素和name属性来创建具名插槽。这样您就可以为一个组件的不同部分定义不同的内容。 以下是一个简单的示例&#xff1a; <template><div><header><slot name"header"></slot></header><mai…...

C++笔试强训day19

目录 1.小易的升级之路 2.礼物的最大价值 3.对称之美 1.小易的升级之路 链接 模拟就行&#xff0c;唯一可能是难点得就是gcd&#xff08;最大公约数&#xff09; #include <iostream> using namespace std; #define int long long const int N 1e5 10; int arr[N];…...

MySQL软件安装基于压缩包

打开mysql官网网址 MySQL :: Download MySQL Community Server 本次针对版本8的安装包方式进行安装&#xff0c;下载成功后接下来对MySQL进行安装 下载后有一个以zip后缀结尾的压缩包文件 对于安装包方式安装&#xff0c;比起可视化安装省去了许多安装步骤&#xff0c;这里直接…...

04 贝尔曼最优公式

贝尔曼最优公式 前言1、Motivating examples2、Definition of optimal policy3、Bellman optimality equation(BOE)&#xff1a;Introduction4、 BOE&#xff1a;Maximization on the right-hand side5、BOE&#xff1a;Rewrite as v f(v)6、Contraction mapping theorem7、BO…...

印象笔记使用技巧

印象笔记&#xff08;Evernote&#xff09;是一款广泛使用的笔记应用&#xff0c;它帮助用户整理个人信息、文件和备忘录。以下是一些提高在印象笔记中效率的使用技巧&#xff1a; ### 1. 使用标签和笔记本组织笔记 - **建立笔记本**&#xff1a;为不同的项目或类别创建笔记本…...

产品设计中的“注册”说明

​在使用网站或应用的时候必不可少的就是账号系统&#xff0c;账号系统有些人可能觉得简单&#xff0c;无非就是账号密码。真的是这样吗&#xff1f; 一个完整的账号系统通常大家会分成四部分&#xff1a; 1.注册&#xff08;手机号、邮箱、用户名/密码限制/验证码&#xff09;…...

【linux学习】多线程(1)

文章目录 线程的概念线程与进程 线程的用法线程的创建多线程 线程的等待线程锁死锁 线程的概念 在Linux中&#xff0c;线程&#xff08;Thread&#xff09;是程序执行流的最小单位&#xff0c;是进程中的一个实体&#xff0c;负责在程序中执行代码。线程本身不拥有系统资源&…...

Leetcode 3149. Find the Minimum Cost Array Permutation

Leetcode 3149. Find the Minimum Cost Array Permutation 1. 解题思路2. 代码实现 题目链接&#xff1a;3149. Find the Minimum Cost Array Permutation 1. 解题思路 这一题的话就是一个动态规划的问题&#xff0c;不过他这个错位着实是把题目变得复杂了不少&#xff0c;唉…...

Python | 为列表中的元素分配唯一值

我们可以给列表中的所有数字分配一个唯一的值&#xff0c;重复时它会保留给它的值。这是一个非常常见的问题&#xff0c;在Web开发中&#xff0c;处理物品id时会遇到。让我们讨论一下解决这个问题的一些方法。 1. 使用enumerate() 列表解析 # initializing list test_list …...

HTML炫酷的相册

目录 写在前面 HTML简介 完整代码 代码分析 系列推荐 写在最后 写在前面 本期小编给大家带来一个炫酷的旋转相册&#xff0c;快来解锁属于你的独家记忆吧&#xff01; HTML简介 HTML&#xff08;全称为超文本标记语言&#xff09;是一种用于创建网页结构和内容的标记语…...

C++笔试强训day20

目录 1.经此一役小红所向无敌 2.连续子数组最大和 3.非对称之美 1.经此一役小红所向无敌 链接 简单模拟即可。 需要注意的是&#xff1a; 除完之后有无余数&#xff0c;若有&#xff0c;则还可以再挨一次打。 #include <iostream> using namespace std; #define in…...

【PHP【实战项目】系统性教学】——使用最精简的代码完成用户的登录与退出

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…...

Linux下的常用基本指令

基本指令 前言一、ls 指令语法功能常用选项举例注意要点关于拼接关于 -a关于文件ls与/的联用ls与根目录ls与任意文件夹ls与常用选项与路径 ls -d与ls -ldls与ll 二、pwd命令语法功能常用选项注意要点window与Linux文件路径的区别家目录 三、cd 指令语法功能举例注意要点cd路径.…...