初识c#委托,delegate,Func,Action

来源:互联网 发布:大学社团网络部职能 编辑:程序博客网 时间:2024/05/29 10:45

委托的使用

法庭上律师为当事人辩护,他真正执行的是当事人的陈词,律师就相当于一个委托对象,而当事人则委托律师对象为自己辩护。
C#中的委托概念也就好比律师对象,它是一个类,委托是类类型,因为只有类才有对象的概念。
C#中的委托可以理解为函数的一个包装,它使得C#中的函数可以作为参数来传递,这在作用上相当于C++的函数指针。C++用户函数指针获取函数的入口地址,然后通过这个指针来实现对函数的操作。
委托的定义和方法的定义类似,只是在定义的前面多了一个delegate关键字,可以被委托包装的方法必须满足以下原则:

  1. 方法的签名必须与委托一致,方法签名包括参数的个数、类型和顺序;
  2. 方法的返回类型要和委托一致,注意,方法的返回类型不属于方法签名的一部分。

例子:

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace DelegateUse{    // 委托使用演示    class Program    {        // 1. 使用delegate关键字来定义一个委托类型        delegate void MyDelegate(int para1, int para2);        static void Main(string[] args)        {            // 2. 声明委托变量d            MyDelegate d;            // 3. 实例化委托类型,传递的方法也可以为静态方法,这里传递的是实例方法            d = new MyDelegate(new Program().Add);            // 4. 委托类型作为参数传递给另一个方法            MyMethod(d);            Console.Read();        }        // 该方法的定义必须与委托定义相同,即返回类型为void, 两个int类型的参数        void Add(int para1, int para2)        {            int sum = para1 + para2;            Console.WriteLine("两个数的和为:"+sum);        }        // 方法的参数是委托类型        private static void MyMethod(MyDelegate mydelegate)        {            // 5.在方法中调用委托            mydelegate(1,2);        }    }}

使用委托的步骤:定义委托类型->声明委托变量->实例化委托->作为参数传递给方法->调用委托。

  1. 定义委托类型:delegate void MyDelegate(int para1, int para2);其定义方式类似于方法的定义,只是多了一个delegate关键字。
  2. 声明委托变量:MyDelegate d;既然委托是一种类型,那么可以使用委托来声明一个委托变量,相当于int a
  3. 实例化委托:d = new MyDelegate(new Program().Add);第二步只是声明了委托变量,但并没有将它实例化。类的实例化使用new关键字实现,而委托也属于类类型,所以委托的实例化也使用new关键字来进行的。这里需要注意的是,委托的实例化是用一个方法名(不能带左右括号)作为参数,并且该方法的定义必须符合委托的定义,即该方法的返回类型。参数个数和类型必须与委托定义中的一样。
  4. 作为参数传递给方法:MyMethod(d);委托使得在C#中,可以把一个方法作为另一个方法的参数,而委托可以看做是一个包装方法的对象。
  5. 在方法中调用委托。MyMethod方法好比是法官,MyMethod方法调用委托,委托再调用方法InstanceMethod。

为什么要引入委托

引入委托之后,就可以把函数作为参数传递给另外一个方法,提高方法的扩展性。
例子:

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace DelegateOrigin{    class Program    {        static void Main(string[] args)        {            // 引入委托之后            // 初始化对象            Program p = new Program();            p.Greeting("李志", p.ChineseGreeting);            p.Greeting("Tommy Li", p.EnglishGreeting);            Console.Read();        }        #region 引入委托之后        // 定义委托类型        public delegate void GreetingDelegate(string name);        // 有了委托之后,可以像如下实现打招呼方法        public void Greeting(string name, GreetingDelegate callback)        {            // 调用委托            callback(name);        }        // 英国人打招呼方法        public void EnglishGreeting(string name)        {            Console.WriteLine("Hello,  " + name);        }        // 中国人打招呼方法        public void ChineseGreeting(string name)        {            Console.WriteLine("你好, " + name);        }        public void JapaneseGreeting(string name)        {            Console.WriteLine("こんにちは, "+name);        }        #endregion         #region 没有委托的情况        //// 不使用委托实现打招呼方法        //public void Greeting(string name,string language)        //{        //    switch (language)        //    {        //        case "zh-cn":        //            ChineseGreeting(name);        //            break;        //        case "en-us":        //            EnglishGreeting(name);        //            break;        //        default:        //            EnglishGreeting(name);        //            break;        //    }        //}        //// 英国人打招呼方法        //public void EnglishGreeting(string name)        //{        //    Console.WriteLine("Hello,  "+name);        //}        //// 中国人打招呼方法        //public void ChineseGreeting(string name)        //{        //    Console.WriteLine("你好, "+name);        //}        #endregion    } }

委托链

委托封装一个方法的情况,可理解为一个律师只为一个当事人辩护。但律师为多个当事人辩护的情况是存在的,C#中委托也同样可以封装多个方法。C#中把封装多个方法的委托称作委托链或多路广播委托。
可以使用 +运算符把委托链接到一个委托对象实例上,也可以用-运算符将某个委托从委托链对象上移除。
例子:

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace MulticastDelegates{    class Program    {        // 声明一个委托类型        public delegate void DelegateTest();        static void Main(string[] args)        {            // 用静态方法来实例化委托            DelegateTest dtstatic = new DelegateTest(Program.method1);            DelegateTest dtinstance= new DelegateTest(new Program().method2);            // 定义一个委托对象,一开始初始化为null,就是不代表任何方法(我就是我,我不代表任何人)            DelegateTest delegatechain = null;            // 使用+符号链接委托,链接多个委托后就成为委托链了            delegatechain += dtstatic;            delegatechain += dtinstance;            // 使用-运算符把dtstatic委托从委托链中移除            delegatechain -= dtstatic;            // 调用委托链            delegatechain();            Console.Read();        }        // 静态方法        private static void method1()        {            Console.WriteLine( "这是静态方法");        }        // 实例方法        private void method2()        {            Console.WriteLine( "这是实例方法");        }    }}

Func委托

Func<T, TResult> 委托封装一个方法,该方法具有一个参数,且返回由 TResult 参数指定的类型的值。使用 Func<T, TResult> 委托时,您无需显式定义一个封装具有单个参数的方法的委托。 

例如,下面的代码显式声明的委托名为 ConvertMethod 和分配的引用 UppercaseString 给其委托实例的方法。

using System;delegate string ConvertMethod(string inString);public class DelegateExample{   public static void Main()   {      // Instantiate delegate to reference UppercaseString method      ConvertMethod convertMeth = UppercaseString;      string name = "Dakota";      // Use delegate instance to call UppercaseString method      Console.WriteLine(convertMeth(name));   }   private static string UppercaseString(string inputString)   {      return inputString.ToUpper();   }}

下面的示例简化了此代码实例化 Func

using System;public class GenericFunc{   public static void Main()   {      // Instantiate delegate to reference UppercaseString method      Func<string, string> convertMethod = UppercaseString;      string name = "Dakota";      // Use delegate instance to call UppercaseString method      Console.WriteLine(convertMethod(name));   }   private static string UppercaseString(string inputString)   {      return inputString.ToUpper();   }}

还可以使用 Func

using System;public class Anonymous{   public static void Main()   {      Func<string, string> convert = delegate(string s)         { return s.ToUpper();};       string name = "Dakota";      Console.WriteLine(convert(name));      }}

还可以分配到的 lambda 表达式 Func

using System;public class LambdaExpression{   public static void Main()   {      Func<string, string> convert = s => s.ToUpper();      string name = "Dakota";      Console.WriteLine(convert(name));      }}

下面的示例演示如何声明和使用 Func

using System;using System.Collections;using System.Collections.Generic;using System.Linq;static class Func{   static void Main(string[] args)   {      // Declare a Func variable and assign a lambda expression to the        // variable. The method takes a string and converts it to uppercase.      Func<string, string> selector = str => str.ToUpper();      // Create an array of strings.      string[] words = { "orange", "apple", "Article", "elephant" };      // Query the array and select strings according to the selector method.      IEnumerable<String> aWords = words.Select(selector);      // Output the results to the console.      foreach (String word in aWords)         Console.WriteLine(word);   }}      

Action委托

Action<T> 委托封装一个方法,该方法只有一个参数并且不返回值。使用方法与Func大致相同。
using System;using System.Windows.Forms;public class TestAction1{   public static void Main()   {      Action<string> messageTarget;       if (Environment.GetCommandLineArgs().Length > 1)         messageTarget = ShowWindowsMessage;      else         messageTarget = Console.WriteLine;      messageTarget("Hello, World!");      }         private static void ShowWindowsMessage(string message)   {      MessageBox.Show(message);         }}

参考资料:

  • 《Learning hard C#学习笔记》
  • https://msdn.microsoft.com/zh-cn/library/bb549151(v=vs.110).aspx
  • https://msdn.microsoft.com/zh-cn/library/018hxwa8(v=vs.110).aspx#中国 (简体中文)
0 0
原创粉丝点击