c#中的泛型委托详解
c#中的泛型委托。
1.一般的委托,delegate,可以又传入参数(<=32),声明的方法为 public delegate void SomethingDelegate(int a);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace delegateSummary {
public delegate void GetIntDelegate( int a); //声明一个委托 public class getIntClass { public static void SetDelegateString( int a,GetIntDelegate getIntDelegate) {
//使用委托 getIntDelegate(a); } public void getInt1( int a) { //方法1 Console.WriteLine( "getInt1方法调用,参数为:" + a); } public void getInt2( int a) { //方法2 Console.WriteLine( "getInt2方法调用,参数为:" + a); } } class Program {
static void Main( string [] args) {
getIntClass gc= new getIntClass(); getIntClass.SetDelegateString(5, gc.getInt1); //方法1,2作为委托的参数 getIntClass.SetDelegateString(10, gc.getInt2); Console.WriteLine( "=====================" ); GetIntDelegate getIntDelegate; getIntDelegate = gc.getInt1; //将方法1,2绑定到委托 getIntDelegate += gc.getInt2; getIntClass.SetDelegateString(100, getIntDelegate); Console.Read(); } } } |
输出结果,注意两种方式的不同,第一种将方法作为委托的参数,第二种是将方法绑定到委托。
2.泛型委托之Action,最多传入16个参数,无返回值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace delegateSummary {
class Program {
static void Main( string [] args) {
TestAction< string >(getString, "WhiteTaken" ); //传入方法 TestAction< int >(getInt, 666); TestAction< int , string >(getStringAndInt, 666, "WhiteTaken" ); Console.Read(); } public static void TestAction<T>(Action<T> action,T p1) { //Action传入一个参数测试 action(p1); } public static void TestAction<T, P>(Action<T, P> action, T p1, P p2) { //Action传入两个参数测试 action(p1,p2); } public static void getString( string a) { //实现int类型打印 Console.WriteLine( "测试Action,传入string,并且传入的参数为:" +a); } public static void getInt( int a) { //实现String类型打印 Console.WriteLine( "测试Action,传入int,并且传入的参数为:" + a); } public static void getStringAndInt( int a, string name) { //实现int+string类型打印 Console.WriteLine( "测试Action,传入两参数,并且传入的参数为:" + a+ ":" +name); } } } |
测试结果:
3.泛型委托之Func,最多传入16个参数,有返回值。(写法与Action类似,只是多了返回值)
4.泛型委托之predicate(不是很常用),返回值为bool,用在Array和list中搜索元素。(没有用到过,等用到了再更新)
/*****************************************************************
在看泛型委托之前还需要先了解委托的概念。
这里讲的委托有两种类型一种是有返回值的,另一种是事件委托。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
//定义有返回值的委托 public delegate string GenricDelegate<T, S>(T title, S author); //定义事件委托。 public delegate void GenricDelegateEnent<E,P>(E Name,P Address); public class GenericDelegateClass<V,F> {
//声明委托 public GenricDelegate<V, F> GdeleValue; //声明事件委托 public event GenricDelegateEnent<V, F> GdEvent = null ; public string GetValues(V title, F author) {
//调用委托 return GdeleValue(title, author); } public GenericDelegateClass() {
} public void InvokeEvent(V name, F address) {
if (GdEvent != null ) {
//调用委托 GdEvent(name, address); } } } |
上面我们定义及调用了泛型委托,接下来就来梆定委托。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
private void btnDelegate_Click( object sender, EventArgs e) {
GenericDelegateClass< string , string > gd = new GenericDelegateClass< string , string >(); //将DelegateReturn事件梆定给GdeleValue gd.GdeleValue = new GenricDelegate< string , string >(DelegateReturn); //将GenericEvent事件梆定给GdEvent gd.GdEvent += new GenricDelegateEnent< string , string >(GenericEvent< string , string >); } public string DelegateReturn<T,S>(T title,S author) {
return title.ToString() + author; } private void GenericEvent<V, F>(V name, F address) {
// } |
在这里我们看到我在梆定DelegateReturn的时候并没有带泛型参数。在这里的泛型参数其实是没什么意义的。因为他的类型取决于调用委托的方法的类型。也就是在前面那段代码中InvokeEvent方法的类型,这里的DelegateReturn要用泛型方法是可以随时跟InvokeEvent的参数类型保持一至。这样梆定后我们再来调用gd.GetValues("my generic post","fastyou");这样调用的其实就是DelegateReturn的方法,这就是委托的好处了,同样调用gd.InvokeEvent("my generic post","fastyou");就是GenericEvent方法。
委托 可以定义自己的类型参数。引用泛型委托的代码可以指定类型参数以创建已关闭的构造类型,就像实例化泛型类或调用泛型方法一样,如下例所示:
1 2 3 4 |
public delegate void Del<T>(T item); public static void Notify( int i) { } Del< int > m1 = new Del< int >(Notify); |
C# 2.0 版具有称为方法组转换的新功能,此功能适用于具体委托类型和泛型委托类型,并使您可以使用如下简化的语法写入上一行:
Del<int> m2 = Notify;
在泛型类内部定义的委托使用泛型类类型参数的方式可以与类方法所使用的方式相同。
1 2 3 4 5 6 7 |
class Stack<T> {
T[] items; int index; public delegate void StackDelegate(T[] items); } |
引用委托的代码必须指定包含类的类型变量,如下所示:
1 2 3 4 5 6 7 |
private static void DoWork( float [] items) { } public static void TestStack() {
Stack< float > s = new Stack< float >(); Stack< float >.StackDelegate d = DoWork; } |
根据典型设计模式定义事件时,泛型委托尤其有用,因为发送方参数可以为强类型,不再需要强制转换成 Object,或反向强制转换。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
delegate void StackEventHandler<T, U>(T sender, U eventArgs); class Stack<T> {
public class StackEventArgs : System.EventArgs { } public event StackEventHandler<Stack<T>, StackEventArgs> stackEvent; protected virtual void OnStackChanged(StackEventArgs a) {
stackEvent( this , a); } } class SampleClass {
public void HandleStackChange<T>(Stack<T> stack, Stack<T>.StackEventArgs args) { } } public static void Test() {
Stack< double > s = new Stack< double >(); SampleClass o = new SampleClass(); s.stackEvent += o.HandleStackChange; } |
/*************************C#泛型委托的用法实例分析
本文实例讲述了C#泛型委托的用法。分享给大家供大家参考。具体分析如下:
冒泡排序大家都知道,例如一个整形数组,可以用冒泡排序来使它按从小到大的顺序排序,
但它仅限于了按整形数组来排序,如何做到按任意类型进行排序呢,例如按一个类的某个属性进行排序?
举例说明:定义一组以类MEmployee为元素的数组,按MEmployee的Salary属性进行排序,类似的可以引伸为对其他类型的比较
元素类定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class MEmployee {
public string Name { get ; private set ; } public decimal Salary { get ; private set ; } public MEmployee( string name, decimal salary) {
this .Name = name; this .Salary = salary; } public override string ToString() {
return string .Format( "{0},{1:C}" , Name, Salary); } public static bool CompareSalary(MEmployee e1, MEmployee e2) //定义一个静态的比较函数 {
return e1.Salary < e2.Salary; } } |
比较类定义:
//BubbleSorter现在已经是一个通用的排序类了,这里委托起到了关键的作用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public class BubbleSorter {
//该函数接收两个参数,第一个为泛型数组参数, //第二个是系统自定义的Func委托,它接收两参数,返回bool类型 public static void Sort<T>(IList<T> sortArray,Func<T,T, bool > comparison) {
for ( int i = 0; i < sortArray.Count; i++) {
for ( int j = i + 1; j < sortArray.Count; j++) {
if (comparison(sortArray[j],sortArray[i])) //调用委托进行大小比较 {
T temp =sortArray[i]; sortArray[i] = sortArray[j]; sortArray[j] = temp; } } } } } |
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
private void button_测试委托3_Click( object sender, EventArgs e) {
MEmployee[] employees = {
new MEmployee( "Ronaldo" ,40000), new MEmployee( "Rivaldo" ,35000), new MEmployee( "CRonaldo" ,80000) }; BubbleSorter.Sort<MEmployee>(employees, MEmployee.CompareSalary); foreach (MEmployee oTmp in employees) {
Console.WriteLine(oTmp.ToString()); } } |
测试结果如下图所示:
/***********************************************************
C#中的多播委托和泛型委托
多播委托
简介
- 每一个委托都是继承自MulticastDelegate,也就是每个都是多播委托。
- 带返回值的多播委托只返回最后一个方法的值
- 多播委托可以用加减号来操作方法的增加或者减少。
- 给委托传递相同方法时 生成的委托实例也是相同的(也就是同一个委托)
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
//声明委托 delegate void MulticastTest(); public class MulticastDelegateTest {
public void Show() {
MulticastTest multicastTest = new MulticastTest(MethodTest); multicastTest(); Action action = new Action(MethodTest); action = (Action)MulticastDelegate.Combine(action, new Action(MethodTest2)); action = (Action)MulticastDelegate.Combine(action, new Action(MethodTest3)); action = (Action)MulticastDelegate.Remove(action, new Action(MethodTest3)); action(); //等同于上面 action = MethodTest; action += MethodTest2; action += MethodTest3; action -= MethodTest3; foreach (Action action1 in action.GetInvocationList()) {
action1(); } Console.WriteLine( "==========" ); action(); Func< string > func = () => { return "我是Lambda" ; }; func += () => { return "我是func1" ; }; func += () => { return "我是func2" ; }; func += GetTest; func += GetTest; //给委托传递相同方法时 生成的委托实例也是相同的(也就是同一个委托) string result = func(); Console.WriteLine(result); Console.WriteLine( "==========" ); } #region 委托方法 public void MethodTest() {
Console.WriteLine( "我是方法MethodTest()1" ); } public void MethodTest2() {
Console.WriteLine( "我是方法MethodTest()2" ); } public void MethodTest3() {
Console.WriteLine( "我是方法MethodTest()3" ); } public string GetTest() {
return "我是方法GetTest()" ; } #endregion } |
泛型委托
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
//泛型委托声明 delegate void GenericDelegate<T>(T t); public class GenericDelegate {
public static void InvokeDelegate() {
GenericDelegate< string > genericDelegate = new GenericDelegate< string >(Method1); genericDelegate( "我是泛型委托1" ); //官方版本(不带返回值) Action< string > action = new Action< string >(Method1); action( "我是泛型委托1" ); //Action<string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string> GenericDelegate< int > genericDelegate1 = new GenericDelegate< int >(Method2); genericDelegate1(2); //官方版本(带回值) Func< string , string > func = new Func< string , string >(Method3); string ret = func( "我是带返回值Func委托" ); Console.WriteLine( ret ); //Func<string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string,string> } #region 委托方法 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 ) {
return str; } #endregion } |
/********************************************************************
C#基础之泛型委托实例教程
本文实例讲述了C#中泛型委托的用法,并以示例形式较为详细的进行了用法分析。分享给大家供大家参考之用。具体如下:
首先,泛型委托是委托的一种特殊形式,虽然感觉看上去比较怪异,其实在使用的时候跟委托差不多,不过泛型委托更具有类型通用性。
就拿C#里最常见的委托EventHandler打比方。在.NET 2.0以前,也就是泛型出现以前,普通的事件处理函数都由EventHandler定义,如下:
1 |
public delegate void EventHandler( object sender, EventArgs e); |
EventHandler指代了这样一类函数,这些函数没有返回值,并且有两个参数,第一个参数是object类型,而第二个参数是EventArgs类型。
而.NET 2.0及其以后的版本,由于泛型的引入,所以一些内建(Built-in)的类、接口、委托都有了各自的泛型版本。EventHandler也不例外,它有了自己的泛型版本:EventHandler<T>,它的定义如下:
1 2 |
[Serializable] public delegate void EventHandler<TEventArgs>( object sender, TEventArgs e) where TEventArgs: EventArgs; |
您应该可以发现,第二个参数的类型由EventArgs变成了TEventArgs,而TEventArgs具体是什么,则由调用方决定。假设IntEventArgs和StringEventArgs都继承于System.EventArgs,那么:
1.EventHandler<IntEventArgs>指代这样一类函数:这些函数没有返回值,有两个参数,第一个参数是object类型,第二个参数是IntEventArgs类型
2.EventHandler<StringEventArgs>指代这样一类函数:这些函数没有返回值,有两个参数,第一个参数是object类型,第二个参数是StringEventArgs类型
其实EventHandler<IntEventArgs>和EventHandler<StringEventArgs>是两个完全不同的委托,它们所指代的函数都分别有着不同的签名形式。请参见下面的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
class IntEventArgs : System.EventArgs { public int IntValue { get ; set ; } public IntEventArgs() { } public IntEventArgs( int value) { this .IntValue = value; } } class StringEventArgs : System.EventArgs { public string StringValue { get ; set ; } public StringEventArgs() { } public StringEventArgs( string value) { this .StringValue = value; } } class Program { static void PrintInt( object sender, IntEventArgs e) { Console.WriteLine(e.IntValue); } static void PrintString( object sender, StringEventArgs e) { Console.WriteLine(e.StringValue); } static void Main( string [] args) { EventHandler<IntEventArgs> ihandler = new EventHandler<IntEventArgs>(PrintInt); EventHandler<StringEventArgs> shandler = new EventHandler<StringEventArgs>(PrintString); ihandler( null , new IntEventArgs(100)); shandler( null , new StringEventArgs( "Hello World" )); } } |