C#泛型委托

news2024/11/27 10:30:53

在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);//传参int

          Func<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--"我是带参的" 类型的参数,并返回一个 string
            Console.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);//委托声明 AnimalPlay
        static 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,我们把这种情况称为 外层变量被匿名函数捕获,它们的生存周期将延长至委托被销毁为止。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1668866.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQL Server共享功能目录显示灰色无法自行选择

SQL Server共享功能目录显示灰色无法自行调整 一、 将之前安装SQL Server卸载干净 二、 清空注册表 1. 打开注册表&#xff0c;winR&#xff0c;输入regedit 2. 注册表-》编辑-》查找&#xff0c;输入C:\Program Files\Microsoft SQL Server\ 3. 注册表-》编辑-》查找&#x…

EfficientNet网络结构详细解读+SE注意力机制+pytorch框架复现

文章目录 &#x1f680;&#x1f680;&#x1f680;前言一、1️⃣ 网络详细结构1.1 &#x1f393; MBConv结构1.2 ✨SE注意力机制模块1.3 ⭐️Depthwise Separable Convolution深度可分离卷积1.3.1 普通卷积操作(Convolution)1.3.2 逐深度卷积&#xff08;Depthwise Convoluti…

一对一WebRTC视频通话系列(六)——部署到公网

本系列博客主要记录一对一WebRTC视频通话实现过程中的一些重点&#xff0c;代码全部进行了注释&#xff0c;便于理解WebRTC整体实现。 本专栏知识点是通过<零声教育>的音视频流媒体高级开发课程进行系统学习&#xff0c;梳理总结后写下文章&#xff0c;对音视频相关内容感…

什么是JVM中的程序计数器

在计算机的体系结构中&#xff1a; 程序计数器&#xff08;Program Counter&#xff09;&#xff0c;通常缩写为 PC&#xff0c;是计算机体系结构中的一个寄存器&#xff0c;用于存储下一条指令的地址。程序计数器是控制单元的一部分&#xff0c;它的作用是确保程序能够按正确…

【动态规划】简单多状态dp问题

1.按摩师 按摩师 思路&#xff1a; class Solution { public:int massage(vector<int>& nums) {//创建dp表//初始化//填表//返回值int n nums.size();if(n 0) return 0;vector<int> f(n);auto g f;f[0] nums[0];for(int i 1; i < n; i){f[i] g[i - 1…

智慧旅游平台开发微信小程序【附源码、文档说明】

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

作为校招新人,他们如何在字节跳动做 AI 研究并中选 ICLR 的?

校招生和实习生在字节跳动&#xff0c;工作一年就中选 ICLR 2024 &#xff0c;这是怎样一种体验&#xff1f; 就在 5 月 7 日至 5 月 11 日&#xff0c;2024 年度国际表征学习大会 ICLR 2024 在奥地利维亚纳举办。该活动是深度学习领域最重要的学术活动之一&#xff0c;由深度学…

五角钱的程序员 | Kafka 是什么?

本文来源公众号“五角钱的程序员”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;Kafka 是什么&#xff1f; 你是一个程序员&#xff0c;假设你维护了两个服务 A 和 B。B 服务每秒只能处理 100 个消息&#xff0c;但 A 服务却每秒…

苹果手机上音乐转换成mp3格式难不难?电脑支持转换吗?支持!

在苹果手机上&#xff0c;有时我们可能会遇到需要将音乐文件转换为MP3格式的情况。这可能是因为某些音乐播放器或设备只支持MP3格式&#xff0c;或者我们想要将音乐文件与其他设备或平台共享。本文将为您详细介绍在苹果手机上如何将音乐转换为MP3格式。 首先&#xff0c;我们需…

贪吃蛇——C语言实践

目录 1. 游戏效果演示 2. 课程目标 3.项目适合对象 4.技术要点 5. Win32 API介绍 5.1 Win32 API 5.2 控制台程序 5.3 控制台屏幕上的坐标COORD 5.4 GetStdHandle 5.5 GetConsoleCursorInfo 5.5.1 CONSOLE_CURSOR_INFO 5.6 SetConsoleCursorInfo 5.7 SetConsoleCurs…

Linux系统——VIM编辑工具

vi/vim vi是一个文本编辑器&#xff0c;用于撰写文档&#xff0c;或者开发程序。vim是vi的增强版 功能一致&#xff0c;可视化效果更好一些。去鼠标化 编辑更加方便 可定制化。 vim编辑器是一个模式化文本编辑器 模式以&#xff1a;编辑模式 进入文档后默认的模式 作用&am…

Midjourney与Stable Diffusion大比拼:AI绘画技术的未来

在当今快速发展的人工智能技术浪潮中&#xff0c;AI绘画软件成为了艺术和技术交汇的新领域。两大巨头——Midjourney和Stable Diffusion&#xff0c;在这一领域中引领风骚&#xff0c;它们以其独特的功能和强大的生成能力&#xff0c;让创作者能够将想象力化为现实。本文将深入…

在Ubuntu 24.04 LTS (Noble Numbat)上安装nfs server以及nfs client

在Ubuntu 24.04 LTS (Noble Numbat)上,我使用的是最小化安装, 当然server版本的Ubuntu在安装的时候可能会有网络不通的问题,解决办法见如下文章: ubuntu 24.04 server 仅NAT模式上网设置静态IP设置-CSDN博客文章浏览阅读489次,点赞9次,收藏3次。在Ubuntu 24.04 上设置网…

YApi的在IDEA中的使用

1 IDEA中插件下载 2 misc.xml的配置 <component name"yapi"><option name"projectToken">XXXXXXXXXX</option><option name"projectId">47</option><option name"yapiUrl">http://XXXX:3000<…

Appium 2.x 安装及使用

由于安全问题&#xff0c;Appium 1.x 版本不再被维护&#xff0c;但想要继续使用Appium进行自动化可以使用 Appium 2.x。 1. 安装Appium 2.x 在过往文章中有介绍过Appium 1.x 的安装&#xff0c;所以一些必备的软件(如&#xff1a;JDK、SDK、node.js、Python)安装就不再细嗦&…

RWA会成为下一个风口吗?有哪些值得关注的项目?

随着加密货币市场的迅速发展和成熟&#xff0c;现实世界资产&#xff08;Real World Assets&#xff0c;RWA&#xff09;正逐渐引起人们的关注&#xff0c;并有望成为下一个加密货币领域的风口。本文将探讨RWA的潜力&#xff0c;以及当前值得关注的项目。 RWA的潜力 RWA代表着…

docker(五):DockerFile

文章目录 DockerFile1、Dockerfile构建过程解析2、DockerFile常用保留字命令FROMMAINTAINERRUNEXPOSEWORKDIRUSERENVADDCOPYVOLUMECMDENTRYPOINT总结 3、案例 DockerFile 1、Dockerfile构建过程解析 官网文档&#xff1a;https://docs.docker.com/reference/dockerfile/ Dock…

SpringBoot3集成WebSocket

标签&#xff1a;WebSocket&#xff0c;Session&#xff0c;Postman。 一、简介 WebSocket通过一个TCP连接在客户端和服务器之间建立一个全双工、双向的通信通道&#xff0c;使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务端主动向客户端推送数据&#xf…

有没有适合女生或者宝妈下班后可以做的副业?

宝妈与上班族女生的新篇章&#xff1a;水牛社副业兼职之旅 在繁忙的职场和温馨的家庭之间&#xff0c;不少女性渴望找到一种既能兼顾家庭又能实现自我价值的兼职方式。对于上班族女生和宝妈们来说&#xff0c;水牛社这样的线上任务平台为她们提供了一个全新的选择。 上班族女…

c++ map,set封装

map 是一个 kv 结构&#xff0c; set 是 k结构。 我们前面模拟实现了 红黑树&#xff0c;但是我们实现的红黑树把 kv 结构写死了&#xff0c;怎么样才能用泛型编程的思想来实现map和set呢 我们先简单看一下原码中是怎么实现的 1.原码实现逻辑 我们打开这里的 stl_set.h 通过…