【C#】学习笔记(2)委托Delegate相关
泛型委托类型,同样是根据杨老师的视频来的。
直接上栗子🌰
1 using System; 2 3 namespace Demo 4 { 5 /// <summary> 6 /// 泛型委托类型 7 /// </summary> 8 /// 9 public delegate T Transformer<T>(T arg); // 这里定义了一个返回类型为T 参数类型为T的泛型委托类型 10 public class Util 11 { 12 public static void Transform<T>(T[] values,Transformer<T> t)// 这里写了一个静态的泛型方法,包含了两个参数,第一个是泛型数组,第二个是泛型委托类型声明一个泛型委托变量 13 { 14 for (int i = 0; i < values.Length ; i++) 15 { 16 values[i] = t(values[i]); // 遍历泛型数组的每一个值,并将遍历出的值通过t.Invoke()调用泛型委托,再将得到的值赋给当前位置的值。 17 } 18 } 19 } 20 public class Program 21 { 22 static int Square(int x) => x * x; 23 public static void Main() 24 { 25 int[] values = { 1, 2, 3 }; 26 Util.Transform(values, Square); 27 foreach (int i in values) 28 { 29 Console.Write(i+" "); // 1 4 9 30 } 31 } 32 } 33 }
同样要注意的是泛型类型的委托同普通的委托一样,参数类型和返回类型必须要严格对应相等。
·Func和Action委托
Func是有返回类型的委托
1 delegate TResult Func<out TResult>(); 2 delegate TResult Func<in T, out TResult>(T arg); 3 delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2); 4 // 输入最高可有有16个即in T1,in T2 ,...,in T16,但是out只有一个!嗯.对了也可以没有输入的.
Action是没有返回类型的委托
1 delegate void Action(); 2 delegate void Action<in T>(T arg); 3 delegate void Action<in T1, in T2>(T1 arg1, T2 arg2); 4 //同样输入最高可到16个.
用Func委托对上面的栗子🌰进行改写。
Before:
After:
为什么可以用Func进行改写呢?
public delegate T Transformer<T>(T arg);
一个名叫Transformer的泛型委托,返回类型是泛型T,参数类型也是泛型T。
Func<T,T> t
满足Func委托的要求。
·委托的应用场景
“委托可以解决的问题,接口都可以解决。”
- 接口只能定义一个方法
- 需要多播能力
- 订阅者需要多次实现接口
栗子🌰
using System; namespace Demo { // 定义一个接口,有一个参数类型为int,返回类型也为int的函数 public interface ITransformer { int Transform(int x); } // Square类实现ITransformer接口 class Square : ITransformer { public int Transform(int x) => x * x; } // Cuber类实现ITransformer接口 class Cuber : ITransformer { public int Transform(int x) => x * x * x; } // 定义一个工具类,里面有一个静态方法用于处理泛型委托类型相关的操作 public class Util { public static void TransformAll<T>(T[] values,Func<T,T> t) { for (int i = 0; i < values.Length; i++) { values[i] = t(values[i]); } } } public class Program { public static void Main() { int[] values1 = { 1, 2, 3 }; Util.TransformAll(values1,new Square().Transform);// 因为不是静态方法所以只能用实例委托的方式 foreach (int i in values1) { Console.Write(i+" "); // 1 4 9 } Console.WriteLine(); int[] values2 = { 1, 2, 3 }; Util.TransformAll(values2, new Cuber().Transform); foreach (int i in values2) { Console.Write(i + " ");// 1 8 27 } } } }
即这种情况下(多次实现接口)适合委托。
委托类型之间互不相容。
编译不会通过。
委托可以接收比他的方法目标更具体的参数类型(ContraVariance),和泛型类型参数一样,委托的variance仅支持引用转换。
1 using System; 2 3 namespace Demo 4 { 5 delegate void StringAction(string s); 6 public class Program 7 { 8 static void ActOnObeject(object o) => Console.WriteLine(o); 9 public static void Main() 10 { 11 StringAction sa = ActOnObeject; 12 sa("Hello");// Hello 13 } 14 } 15 }
- int 到 long数值类转换非引用转换,所以不可以
- int 到 object进行了装箱,所以也是不可以的
委托的返回类型也是可以具体化
1 using System; 2 3 namespace Demo 4 { 5 delegate object ObjectRetriever(); 6 public class Program 7 { 8 static string RetrieveString() => "Hello"; 9 public static void Main() 10 { 11 ObjectRetriever or = RetrieveString; 12 Console.WriteLine(or()); // Hello 13 } 14 } 15 }
委托类的类型就是委托实例的类型,即or()也是object类的。
自己理解画的图,如有错误欢迎指出。
这里有个小彩蛋~✨✨