【写给Cpp选手的C#教程】委托篇
2021/10/5 11:11:18
本文主要是介绍【写给Cpp选手的C#教程】委托篇,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
委托的简单使用
本人对委托的理解:C中的函数指针。用一个变量存储函数,方便传递和使用。
按照如下方法使用:
delegate int Dele(int a); class Program { static int pow(int a) { return a * a; } static void Main(string[] args) { //全写为dele myPow = new dele(pow); Dele myPow = pow; //全写为myPow.Invoke(3); myPow(3); } }
很容易想到,我们可以往函数中传入委托,进行解耦。
参数或返回值为委托的函数被称为高阶函数(high-order function)
delegate int Dele(int x); class Program { static int Square(int x) { return x * x; } static void Main() { int[] values = { 1, 2, 3 }; Transform(values, Square); } //Transform就是一个高阶函数 static void Transform(int[] values, Dele t) { for (int i = 0; i < values.Length; i++) //values[i] = Square(values[i]) { values[i] = t(values[i]); } } }
多播委托
我们的委托可以存放一个函数列表,调用时调用整个列表。本质是new一个委托对象,然后重新赋值。
delegate int NumDele(int a); class Program { static int Pow2(int a) { return a * a; } static int Pow3(int a) { return a * a * a; } static int Pow4(int a) { return a * a * a * a; } static void Main() { NumDele d = null; //往函数列表中增加新的函数 d += Pow2; d += Pow3; d += Pow4; //现在d中的内容:Pow2->Pow3->Pow4 //删除指定函数 d -= Pow3; //现在d中的内容:Pow2->Pow4 Console.Write(d(3)); //返回值为3 * 3 * 3 * 3 = 81,Pow2的返回值被丢弃 } }
委托和对象
你若细看便会发现,上面给委托赋值的函数全部都是static静态函数。
如果我们将实例A的函数F赋值给委托C,那么委托C不仅需要考虑函数F,还需要考虑实例A
可以通过如下方法获取实例:
delegate int NumDele(int a); class Source { public int Pow2(int a) { return a * a; } } class Program { static void Main() { Source s = new Source(); NumDele d = s.Pow2; Console.WriteLine(d.Target);//TestSharp.Source Console.WriteLine(d.Target == s);//True Console.WriteLine(d.Method);//Int32 Pow2(Int32) } }
委托和泛型
委托可以包括泛型类型参数:
public delegate T Dele<T>(T prop);
之后我们就可以进行一些诸如Cpp中algorithm库中的一些,泛型算法的操作(不过下面这个例子并不是泛型算法)
public delegate T Dele<T>(T val); class Program { static int square(int x) { return x * x; } static double devide(double x) { return x / 2; } static void changeArray<T>(T[] arr, Dele<T> opt) { for (int i = 0; i < arr.Length; i++) arr[i] = opt(arr[i]); } static void Main() { int[] iArr = { 1, 2, 3 }; double[] dArr = { 5.4, 2.7, 9.8 }; //对于int类型的数组,使用square函数对其进行加工 changeArray(iArr, square); //iArr变成了[1 , 4 , 9] //对于double类型的数组,使用devide函数对其进行加工 changeArray(dArr, devide); //dArr变成了[2.7 , 1.35 , 4.9] } }
如果我们经常需要用到泛型委托,然后每次都需要自己进行定义和声明,那很明显很烦人。后面C#很贴心的减少了我们的套路活,整出了Func<>和Action<>。
对于Func<T1,T2,T3...>而言,最后一个T是返回值,其余的T都是参数。
对于Action<T1,T2,T3...>而言,所有的T都是参数。
//public delegate T Dele<T>(T val); //static void changeArray<T>(T[] arr, Dele<T> opt) static void changeArray<T>(T[] arr,Func<T,T> opt) //使用Func的写法,就不需要声明Dele了
委托的兼容性
①委托的类型不同,不能赋值
②委托指向相同函数,则认为其是等价的
public delegate void D1(); public delegate void D2(); class Program { static void Func() {} static void Main() { D1 d1 = Func; //D2 d2 = d1; 如果这么写会报错 D2 d2 = new D2(d1); //这么写才行 D1 d3 = Func; D2 d4 = Func; d3==d4 //True } }
③跟委托绑定的函数,其参数可以是委托的参数的父类、子类
public delegate void StringDele(string s); class Program { static void ObjectFunc(object o) { } static void Main() { StringDele s = ObjectFunc; s("hello world"); //string参数会隐式变换为object参数 } }
一般的,传子类是正常的多态行为。传父类被称为逆变。
④跟委托绑定的函数,其返回值可以是委托的返回值的父类、子类
public delegate object objectDele(); class Program { static string strFuc() { return "hello"; } static void Main() { objectDele s = strFuc; s(); } }
objectDele想要返回object,但如果绑定的函数返回object的子类,那么也是可以的。
函数的返回值是委托返回值的子类,这种情况被称为协变。
⑤泛型委托相关
我们需要将只用于返回值的类型参数标记为协变(out),将只用于参数的类型参数标记为逆变(in)
其实,Func和Action的定义可以如下理解:
delegate TResult Func<in T1,in T2,...,out TResult>(T1 prop1,T2 prop2,...); delegate void Action<in T1,in T2,...>(T1 prop1,T2 prop2,...);
然后吧,我们的泛型委托也可以如同之前定义的委托那样,完成逆变和协变了。
这篇关于【写给Cpp选手的C#教程】委托篇的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2022-03-01沐雪多租宝商城源码从.NetCore3.1升级到.Net6的步骤
- 2024-11-15C#中怎么从PEM格式的证书中提取公钥?-icode9专业技术文章分享
- 2024-11-14云架构设计——如何用diagrams.net绘制专业的AWS架构图?
- 2024-05-08首个适配Visual Studio平台的国产智能编程助手CodeGeeX正式上线!C#程序员必备效率神器!
- 2024-03-30C#设计模式之十六迭代器模式(Iterator Pattern)【行为型】
- 2024-03-29c# datetime tryparse
- 2024-02-21list find index c#
- 2024-01-24convert toint32 c#
- 2024-01-24Advanced .Net Debugging 1:你必须知道的调试工具
- 2024-01-24.NET集成IdGenerator生成分布式全局唯一ID