C#委托詳解(3):委托的實現方式大全(續)


接上篇(C#委托詳解(2):實現方式大全),本篇繼續介紹委托的實現方式。

4、Action<T>和Func<T>委托

  使用委托時,除了為每個參數和返回類型定義一個新委托類型之外,還可以使用.NET Framework提供的泛型委托Action<T>和Func<T>,它們提供了從無參一直到最多16個參數的重載,如果方法需要獲取16個以上的參數,就必須定義自己的委托類型,但這種情況應該是及其罕見的。其中Action<T>類可以調用沒有返回值的方法,Func<T>允許調用帶返回類型的方法。

  所以對於上一代碼例子中的委托可以使用Func<double T, out Tresult>這樣實現:

    Func <double, double> operations = MathOperations.MultiplyByTwo;

  等價於:

    delegate double Operations(double x);
    Operations operations = MathOperations.MultiplyByTwo;
    即省略了對於委托類的定義。
  下面這個例子使用泛型委托實現了一個普通的冒泡排序算法,來看看跟普通的冒泡排序有什么不一樣的:
  class BubbleSorter
    {
        static public void Sort<T>(IList<T> sortArray, Func<T, T, bool> comparison)
        {
            bool swapped = true;
            while (swapped)
            {
                swapped = false;
                for (int i = 0; i < sortArray.Count - 1; i++)
                {
                    if (comparison(sortArray[i+1], sortArray[i]))
                    {
                        T temp = sortArray[i];
                        sortArray[i] = sortArray[i + 1];
                        sortArray[i + 1] = temp;
                        swapped = true;
                    }
                }
            } 
        }
    }

可以看到,代碼實現沒有什么不同,不同的是方法簽名,第一個參數類型是IList<T>,它可以支持傳入各種集合數據,第二個傳入參數為一個委托對象,代表的是要排序的對象T的一個方法,這個方法會對兩個對象T的大小進行比較,返回一個boolean類型的值,具體使用方法可以查看下面這段代碼。

    class Student //需要排序的對象類型
    {
        public Student(string name, int salary)
        {
            this.Name = name;
            this.Age = salary;
        }

        public string Name { get; private set; }
        public int Age { get; private set; }

        public override string ToString()
        {
            return string.Format("{0}, {1:C}", Name, Age);
        }

        public static bool CompareAge(Student e1, Student e2)
        {
            return e1.Age < e2.Age;
        }
    }

    class Program
    {
        static void Main()
        {
            Student[] students =
            {
                new Student("zhangsan", 20),
                new Student("lisi", 12),
                new Student("wangwu", 25),
                new Student("zhaoliu", 10),
            };

            BubbleSorter.Sort(students, Student.CompareAge); //傳入對象數組,和一個方法地址
            foreach (var student in students)
            {
                Console.WriteLine(student);
            }
        }
    }

  上述代碼中展示了委托的精髓,即將方法作為參數傳遞給其他方法,以增加代碼的靈活性。(不清楚的童鞋一定仔細體會這種用法。)

 

5、匿名方法

  使用匿名方法定義委托與前面的定義沒有什么區別,只是在實例化委托時,有一點區別。

    class Program
    {
        static void Main()
        {
            double width = 12;

            Func<double, double> square = delegate(double length)  //這里的square是委托類型的實例
            {
                length *= width;
                return length;
            };
            Console.WriteLine(square(10));
        }
    }

  匿名方法的優點是減少了要編寫的代碼,不必定義僅由委托使用的方法。但如果需要用匿名方法多系編寫同一個功能時就不建議使用匿名方法了。

6、Lambda表達式

  C#3.0開始支持Lambda表達式,可以使用其代替匿名方法。使用方法可以參考下面的例子:

            //1、不獲取任何參數
            Func<string> f = () => "lining";
            //2、一個參數(可以顯示指定類型也可以使用類型推斷)
            Func<int, string> f1 = (int n) => n.ToString();
            Func<int, string> f2 = (n) => n.ToString();
            Func<int, string> f3 = n => n.ToString();
            //3、一個或多個參數
            Func<int, int, string> f4 = (int n1, int n2) => (n1 + n2).ToString();
            Func<int, int, string> f5 = (n1,n2) => (n1+n2).ToString();

  Lambda省去了書寫方法,命名方法及傳遞方法的過程,可以減少代碼量,提高編程效率。但其並沒有對代碼的執行效率帶來優勢。

  另外建議不要濫用lambda表達式,其對於調試和單步執行會帶來一定的挑戰。對於三行以上的代碼推薦自己手動寫一個方法,這樣無論對於代碼的可讀性還是可服用性都是有益的。

  

本篇結束,對於委托的實現方式就先介紹這些,下一篇將介紹委托的Invoke,BeginInvoke和EndInvoke方法。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM