1. 程式人生 > >Action和Func泛型委託,委託,泛型,匿名函式,Lambda表示式的綜合使用

Action和Func泛型委託,委託,泛型,匿名函式,Lambda表示式的綜合使用

前言

在上篇文章C#中委託(delegate)和多播委託的理解中已經基本瞭解了委託的用法。 由於委託封裝的方法我們不一定知道其傳入的引數和返回值,例如之前說的的排序方法—————在物件的排序演算法中,需要對物件進行比較,而不同物件比較的方法不同,所以比較兩個物件的方法的引用可以作為引數傳遞到排序演算法中,這個時候就需要傳遞方法。 當我們要生成一個封裝比較物件的方法的委託時,我們並不知道該方法傳入物件是什麼,所有我們必須引入泛型的概念來輔助委託的使用。

Action<T>Func<T>泛型委託

除了為每個引數和返回型別定義一個新委託型別外(基本的委託定義方法),還有就是使用Action<T>

Func<T>定義委託,Action<T>委託表示引用一個void返回型別的方法,且最多可以傳遞16中引數;Func<T>類似,但允許呼叫帶返回值的方法。

注意對比普通委託泛型委託的定義和使用的區別。

泛型委託的定義和使用: 對於上篇加減的例子,可以直接將Func<int, int,int>型別的委託作為引數:

public int numMethod(int num1, int num2, Func<int, int,int> callback)
        {
            return callback(num1,num2);
        }

這兩種方法的區別就在於,我們可以跳過普通委託宣告委託物件的過程,其實我們通過檢視元資料就可以看出,其時是框架給我們封裝好了Func<int, int,int>方法,其實普通委託泛型委託並無太大區別:

public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);

在我們呼叫Func<int, int,int>方法是其實還是生成了一個委託物件,該委託封裝的方法的引數和返回值的型別會自動設定為我們例項該委託的方法的引數和返回值,所以我們使用了來代表任意型別的引數和返回值;

總結

Action<T>Func<T>泛型委託普通委託,沒有本質區別,普通委託是手動設定委託物件的引數和返回值,而泛型委託會根據我們傳入的方法的引數和返回值自動設定其對應的委託物件; 更加具體的理解就是:

如果普通委託可以封裝的具有相同型別引數和返回值的方法,而泛型委託可以封裝的就是引數和方法值的型別具有相同對應關係的方法。

那麼這樣帶來的好處有什麼? 匿名方法Lambda表示式 的使用 可以通過下面這個例項體現出來

重點

這個例項裡泛型委託,匿名方法,Lambda表示式,泛型都有出現,是一個非常好的例項!還出現了另一種泛型委託———Comparison<in T>

class Program
    {
        static void Main(string[] args)
        {
            List<StudentScore> lst = new List<StudentScore>()//需要被排序的物件組
            {
                new StudentScore("A",50),
                new StudentScore("B",60),
                new StudentScore("C",70),
                new StudentScore("D",80),
                new StudentScore("E",93),
                new StudentScore("F",69),
                new StudentScore("G",36),
                new StudentScore("H",76),
                new StudentScore("I",66),
                new StudentScore("J",98)
            };
            //方法一:通過比較兩個物件的匿名函式採用Lambda表示式,來宣告該委託
            Func<StudentScore, StudentScore, bool> fun = (x, y) => x.score < y.score;
            //方法二:通過比較兩個物件方法,宣告該泛型委託
            //Func<StudentScore, StudentScore, bool> fun = compare;
            HighestScores(lst, fun);
            //方法三:直接將比較物件的方法傳入
            //HighestScores(lst, compare);
            Console.ReadLine();

        }

        static public void HighestScores<T>(IList<T> sourceArray, Func<T, T, bool> comp)
        {
            int cnt = Convert.ToInt32((float)sourceArray.Count * 0.2);//前百分之二十
            List<T> lst = sourceArray.ToList();

            lst.Sort((x, y) => comp(x, y) == true ? 1 : -1);//Sort的一個過載引數為Comparison<T>泛型委託
            ///Sort的引數為一個類似於Func<>的表示式,這裡給它賦的為一個Lambda表示式,
            ///當然這裡也同上面的方法二一樣可以將匿名方法抽取出來
            ///相當於Comparison<T> comparison=(x, y) => comp(x, y) == true ? 1 : -1;
            ///其中:
            ///public void Sort(Comparison<T> comparison);
            ///public delegate int Comparison<in T>(T x, T y);
            ///其中Comparison<in T>和前面的Func<>功能類似
            
            foreach (T t in lst.Take(cnt))//返回排序好物件組的前cnt個物件
                Console.WriteLine(t);
        }

        static public bool compare(StudentScore x ,StudentScore y)
        { 
            return x.score < y.score?true : false;
        }
    }

    class StudentScore
    {
        public StudentScore(string n, int s)
        {
            this.name = n;
            this.score = s;
        }

        public string name;
        public int score;

        public override string ToString()
        {
            return string.Format("{0} {1}", this.name, this.score);
        }
    }