C# 委托自我摸索深入

1 篇文章 0 订阅

了解知识:

委托可理解成 升级版的指针

一切都是从地址开始:
变量:以某个地址为起点的一段内存中所存储的值
函数:以某个地址为起点的一段内存中所存储的一组指令

直接调用:通过函数名来调用函数,通过函数名直接获得函数所在地址并开始执行
间接调用:通过(函数指针)来调用函数,通过读取(函数指针)里的值获得函数所在的地址并开始
执行

一、系统自带委托

1.定义一个类,创建函数

//定义一个类,创建函数
class AddPoint
{
	public int Add(int a,int b){
		return a+b;
	}

	public void ActMethod(){
		Console.WriteLine("这是一个Action方法");
	}
}

2.使用系统自带的委托(Func委托、Action委托)

//先实例化AddPoint类
AddPoint ap = new AddPint();
//委托也是一种类,也需要实例化,但是对标是函数方法
Action action = new Action(ap.ActMethod);
//调用Action委托的函数
action.Invoke();
//也可以写成
action();

//Func委托实例化,对标函数方法
Func<int,int,int> func = new Func<int,int,int>(ap.Add);
//调用Func委托的函数,因为Func是有返回值的(最后一个),所以用一个变量取返回值
int num = func(12,13);
//输出
Console.WriteLine(num);
//控制台停留
Console.ReadLine();

实例代码,可以直接跑

using System;

namespace weituo
{
    class Program
    {
        static void Main(string[] args)
        {
            AddPoint ap = new AddPoint();
            Action action = new Action(ap.ActMethod);
            action();
            action.Invoke();
           
            Func<int, int, int> func = new Func<int, int, int> (ap.Add);
            int b = func(2, 3);
            Console.WriteLine(b);
           
            Console.WriteLine(func(20,30));
            Console.ReadLine();
        }

        class AddPoint {
            public int Add(int a, int b)
            {
                int z = a + b;
                return z;
            }

            public void ActMethod() {
                Console.WriteLine("Action方法");
            }
        }
    }
}

结果:

在这里插入图片描述

二、自定义委托

1.声明自定义委托

//委托声明 返回值数据类型 自定义委托名 (需要委托的函数输入)
//比大小
public delegate double BigEquip (float a ,float b);
//是否相等
public delegate bool CompareEquip (int a ,double b);

2.类中定义两个方法

//AddPoint类中定义两个方法
public double BE(float a,float b)
{
	double an;
	
	if (a > b)
	{ an = a; }
	else
	{ an = b; }
	
	return an;
}

public bool CE(int a,double b)
{
	return a==b;
}

3.在实现类中调用

//在实现类中进行调用
static void Main(string[] args)
{
	//类实例化
	AddPoint ap = new AddPoint();
	//委托实例化,并绑定对应的函数方法
	BigEquip be = new BigEquip(ap.BE);
	CompareEquip ce = new CompareEquip(ap.CE);
	//输出
	Console.WriteLine(be(2f,3f));
	Console.WriteLine(ce(2,3));
	  
}

实例代码,可以直接跑

using System;

namespace weituo
{
    class Program
    {
        //比大小
        public delegate double BigEquip(float a, float b);
        //是否相等
        public delegate bool CompareEquip(int a, double b);
        
        static void Main(string[] args)
        {
            //类实例化
            AddPoint ap = new AddPoint();
            //委托实例化,并绑定对应的函数方法
            BigEquip be = new BigEquip(ap.BE);
            CompareEquip ce = new CompareEquip(ap.CE);
            //输出
            Console.WriteLine(be(2f, 3f));
            Console.WriteLine(ce(2, 3));
            
			Console.ReadLine();
        }

        class AddPoint {
            public double BE(float a, float b)
            {
                double an;

                if (a > b)
                { an = a; }
                else
                { an = b; }

                return an;
            }

            public bool CE(int a, double b)
            {
                return a == b;
            }
            
        }
    }
}

结果:

在这里插入图片描述

三、实际作用:委托链

//创建一个委托
public delegate void MyDelegate();

static void Main()
{
	//委托实例化并传值
    MyDelegate myDelegate1 = Method1;
    MyDelegate myDelegate2 = Method2;

    // 创建委托链
    MyDelegate myDelegateChain = myDelegate1 + myDelegate2;

    // 调用委托链中的方法
    myDelegateChain();

    // 从委托链中移除委托实例
    myDelegateChain -= myDelegate2;

    // 再次调用委托链中的方法
    myDelegateChain();
}

static void Method1()
{
    Console.WriteLine("Method 1");
}

static void Method2()
{
    Console.WriteLine("Method 2");
}
————————————————
版权声明:本文为CSDN博主「喵叔哟」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/gangzhucoll/article/details/131750446

四、实际作用:回调函数

1.先自定义一个委托
	public delegate void ID(string basic);


2.创建一个与委托想匹配的方法
	static void method1(string basic)
	{
		Console.WriteLine("当前状态:" + basic);
	}


3.定义一个类,类中定义一个方法调用这个委托并实例化
	class ZhuTi
		{
			//方法是实例化委托
			public void method2(ID id)
			{
				Console.WriteLine("启动状态");
				Thread.Sleep(2000);
				Console.WriteLine("运行状态");
				Thread.Sleep(2000);

				id("重新开始");
			}
		}


4.实例化类,实现类中的方法(给委托与方法实现连接)
	static void Main()
		{
			ZhuTi zhuti = new ZhuTi();
			zhuti.method2(method1);
		}(方便自我理解,不一定对)
一共三个类
1.创建委托(1)
2.与委托相匹配的方法(方法1(2)
3.定义另一个方法2(此时将委托先实例化)(3类) 
4.调用方法2的时候将方法1写入(2)

因为创建委托,必做的两步就是实例化和传值
而与此同时,委托必须要有匹配的方法(值),因此就有以上的顺序步骤

可以跑的程序奉上

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace weituo
{
	public delegate void ID(string basic);
	
	class ZhuTi
	{
		public void method2(ID id)
		{
			Console.WriteLine("启动状态");
			Thread.Sleep(2000);
			Console.WriteLine("运行状态");
			Thread.Sleep(2000);

			id("重新开始");
		}
	}
	
	class Class1
    {
		static void Main()
		{
			ZhuTi zhuti = new ZhuTi();
			zhuti.method2(method1);
		}

		static void method1(string basic)
		{
			Console.WriteLine("当前状态:" + basic);
		}
		
	}
}

五、实际作用:我也没有感受到

将不同的产品装入盒子中(普通的方式写这段代码)

//可直接跑
using System;

namespace QianTao
{
	class text
	{
		static void Main(string[] args)
		{
			//最简单的先将全部类实例化
			Product product1 = new Product();
			Box box1 = new Box();
			WrapFactory wrapFactory = new WrapFactory();
			ProductFactory productFactory = new ProductFactory();

			//套娃开始,将一个个东西装入
			//先把产品确定好
			product1 = productFactory.ToyCar();
			//将产品装入盒子中
			box1 = wrapFactory.install(product1);
			//输出
			Console.WriteLine("box1装的是: " + box1.Product.Name);

			//另一种写法
			Box box2 = wrapFactory.install(productFactory.ToyDoll());
			Console.WriteLine("box2装的是: " + box2.Product.Name);
		}
	}

	//产品
	class Product
	{
		//产品里的内容是产品名
		public string Name { get; set; }
	}

	//盒子(用来装产品的)
	class Box
	{
		//盒子里的内容是产品
		public Product Product { get; set; }
	}

	//将产品打包到盒子中
	class WrapFactory
	{
		//所以输入是产品,返回的是盒子
		public Box install(Product product)
		{
			//实例化Box
			Box box = new Box();
			//将产品装入盒子
			box.Product = product;
			return box;
		}
	}

	//生产各种各样的产品
	class ProductFactory
	{
		public Product ToyCar()
		{
			//实例化产品
			Product product = new Product();
			//赋值给产品
			product.Name = "玩具车";
			return product;
		}

		public Product ToyDoll()
		{
			//同上
			Product product = new Product();
			product.Name = "玩偶";
			return product;
		}

	}
}

用委托的方式写:

//可直接跑
using System;

namespace QianTao
{
	class text
	{
		static void Main(string[] args)
		{
			//日常实例化
			ProductFactory productFactory = new ProductFactory();
			WrapFactory wrapFactory = new WrapFactory();
			

			//调用委托的第一种写法
			Func<Product> func1 = new Func<Product> ( productFactory.ToyCar );
			Box box1 = new Box();
			box1 = wrapFactory.install(func1);
			Console.WriteLine("box1装的是:" + box1.Product.Name);

			//节省写法;
			Func<Product> func2 = productFactory.ToyDoll;	//不知道会不会不够严谨
			Box box2 = wrapFactory.install(func2);
			Console.WriteLine("box2装的是:" + box2.Product.Name);
		}
	}

	//产品
	class Product
	{
		//产品里的内容是产品名
		public string Name { get; set; }
	}

	//盒子(用来装产品的)
	class Box
	{
		//盒子里的内容是产品
		public Product Product { get; set; }
	}

	//将产品打包到盒子中
	class WrapFactory
	{
		//所以输入是产品,返回的是盒子
		//这里将产品替换成委托,但是委托的返回值依旧是产品
		public Box install(Func<Product> func)
		{
			Box box = new Box();
			box.Product = func();
			return box;
		}
	}

	//生产各种各样的产品
	class ProductFactory
	{
		public Product ToyCar()
		{
			Product product = new Product();
			product.Name = "玩具车";
			return product;
		}

		public Product ToyDoll()
		{
			Product product = new Product();
			product.Name = "玩偶";
			return product;
		}

	}
}

以上三种实际作用,在我看来就是取代一个方法,相当于用一个变量去取代一个方法,等需要用这个方法的时候,就调用这个变量。

六、高级实际作用:多播委托

一个委托里包含多个方法,从我们一开始接触委托,其实看到的委托一直是一个委托对标一个方法,现在多播委托是,一个委托对标多个方法,当然方法肯定要同一类型。

多播委托是按照顺序连续调用方法,因此,不可能有返回值,所以返回值位void,否则就只能得委托中最后一个方法的结果

using System;
using static Program.text;

namespace Program
{
    class Program
    {
        static void Main(string[] args)
        {
        	//将委托实例化,并将方法对标Poet
            DuoBo duobos = Poet;
            //将方法Fencer传入委托中
            duobos += Fencer;
            //定义一个string类型
            string name = "李白";
            Console.WriteLine("第一种展示方式");
            //将实例化的委托种的输入赋值为name
            duobos(name);
            Console.WriteLine("第二种展示方式");
            //返回委托的调用列表,这里的delegates列表中存储的是Duobo类型的委托
            Delegate[] delegates = duobos.GetInvocationList();
            //foreach遍历
            foreach (DuoBo duobo in delegates)
            {
                duobo(name);
            }
        }
    }

    class text
    {
    	//自定义一个委托,不需要返回值,输入有一个,类型为string
        public delegate void DuoBo(string name);

		//定义一个名为Poet方法,不需要返回值,输入有一个,类型为string
        public static void Poet(string name)
        {
            Console.WriteLine("诗仙:" + name);
        }

		//定义一个名为Fencer方法,不需要返回值,输入有一个,类型为string
        public static void Fencer(string name)
        {
            Console.WriteLine("剑仙: " + name);
        }
    }
}

emmmmm,上面有些程序的结果忘记截图,问题不大

在这里插入图片描述

上文总结下来的多播委托,其实就是 委托 = 方法1,接着就是 委托 += 方法2,可以理解成,不断将后续方法塞进第一个方法,最后就是使用委托,委托(); 因此调用第一个方法就把所有方法按照顺序实现出来。

七、高级实际作用:隐式异步调用(使用的委托BeginInvoke)

在使用委托隐式异步调用的时候遇到这个问题。

原因是因为我创建的是.NET Core项目,但是在.NET Core中不支持Action.BeginInvoke(null, null)的委托异步调用方法。

目前的解决办法是重新创建一个.NET Framework项目(测试用的是4.5.2),把代码重新复制过去后,就没有异常了。
———————————————— 版权声明:本文为CSDN博主「爱吃柚子的梨」的原创文章,遵循CC 4.0
BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42545675/article/details/104071939

最近学习委托及异步调用碰到了这个报错Unhandled exception. 
System.PlatformNotSupportedException: Operation is not supported on this platform. 
at System.Action.BeginInvoke(AsyncCallback callback, Object object),很头疼,.net和.net core平台都有这个问题。
一查原来是更新后推荐使用(TAP)新的异步编程来实现,原来的BeginInvoke()不再支持了,亲测以下两篇文章都有帮助,谨此记录下。
       
       
       Migrating Delegate.BeginInvoke Calls for .NET Core
       
       
       System.PlatformNotSupportedException:“Operation is not supported on this platform.”
————————————————
版权声明:本文为CSDN博主「dark9spring」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/dark9spring/article/details/117922155

因为我用的版本是.NET 5.0 ,所以就不打算去专门测试了,感兴趣的可以自己试一下,用下面这个取代一下效果

七、高级实际作用:隐式异步调用(使用的Thread)

using System;
using System.Threading;

namespace YiBu
{
    class Program
    {
        static void Main(string[] args)
        {
            Student st1 = new Student() { ID = 1, Pencolor = ConsoleColor.Red };
            Student st2 = new Student() { ID = 2, Pencolor = ConsoleColor.Yellow };

            Thread th1 = new Thread(st1.DrawColor);
            Thread th2 = new Thread(st2.DrawColor);

            //ac1.Invoke();
            //ac2.Invoke();

            th1.Start();
            th2.Start();

            for(int a = 0; a < 5; a++)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("Student{0} Draw Color", a);
                Thread.Sleep(800);
            }

        }
    }


    class Student
    {
        public int ID { get; set; }
        public ConsoleColor Pencolor {get; set;}

        public void DrawColor() 
        {
            for (int i = 0; i < 5; i++)
            {
                Console.ForegroundColor = Pencolor;
                Console.WriteLine("Student{0} Draw Color {1} hours", ID, i);
                Thread.Sleep(1000);
            }
        }
    }
}

输出结果(互相占用抢资源导致这种情况)

在这里插入图片描述
正常情况应该如下

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

走丢的男孩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值