.Net自帶的委托類型—Func,Action 和 Predicate


委托是一個類,它定義了方法的類型,使得可以將方法當作另一個方法的參數來進行傳遞。

與其他的類不同,委托類具有一個簽名,並且它只能對與其簽名匹配的方法進行引用。

一、自定義委托類型

1.語法結構:訪問修飾符 delegate 返回類型 委托類型名稱(參數列表);

例如:

// 聲明一個委托類型,兩個參數均為int類型,返回值為int類型
public delegate int Calc(int a, int b);

自定義的委托可以不帶參數,也可以沒有返回值。

 

接下來我們看一個例子怎么使用委托

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 委托
{
    class Program
    {
        // 聲明一個委托類型,兩個參數均為int類型,返回值為int類型
        public delegate int Calc(int a, int b);

        // 定義和委托簽名一致的方法(參數類型和個數,返回值類型均一致)
        static int Add(int a, int b)
        {
            return a + b;
        }

        static int Sub(int a, int b)
        {
            return a - b;
        }

        static int Multi(int a, int b)
        {
            return a * b;
        }

        static int Divis(int a, int b)
        {
            if (b == 0)
            {
                throw new Exception("除數不能為0!");
            }

            return a / b;
        }

        static void Main(string[] args)
        {
            Console.WriteLine("請輸入第一個數:");
            int a = int.Parse(Console.ReadLine());

            Console.WriteLine("請輸入第二個數:");
            int b = int.Parse(Console.ReadLine());

            // 定義一個Calc委托類型的變量,把和該委托簽名一致的Add方法的引用賦值給變量
            Calc method = Add;
            Console.WriteLine("加法運算:{0}+{1}={2}", a, b, method(a, b));

            method = Sub;
            Console.WriteLine("減法法運算:{0}-{1}={2}", a, b, method(a, b));

            method = Multi;
            Console.WriteLine("乘法運算:{0}×{1}={2}", a, b, method(a, b));

            method = Divis;
            Console.WriteLine("除法運算:{0}÷{1}={2}", a, b, method(a, b));

            Console.ReadKey();
        }
    }
}


2.匿名方法

給上述委托變量賦值時,必須先定義好一個和委托簽名一致的方法。使用匿名方法,你就無需先定義好那些方法,直接通過delegate語法給委托變量賦值。

匿名方法的結構:delegate(參數列表){函數體};

例如:

Calc method = delegate(int x, int y)
            {
                return x + y;
            };


使用匿名方法重新實現上述例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 匿名方法
{
    class Program
    {
        // 聲明一個委托類型,兩個參數均為int類型,返回值為int類型
        delegate int Calc(int a, int b);

        static void Main(string[] args)
        {
            Console.WriteLine("請輸入第一個數:");
            int a = int.Parse(Console.ReadLine());

            Console.WriteLine("請輸入第二個數:");
            int b = int.Parse(Console.ReadLine());

            // 定義一個Calc委托類型的變量
            Calc method = delegate(int x, int y)
            {
                return x + y;
            };
            Console.WriteLine("加法運算:{0}+{1}={2}", a, b, method(a, b));

            method = delegate(int x, int y)
            {
                return x - y;
            };
            Console.WriteLine("減法法運算:{0}-{1}={2}", a, b, method(a, b));

            method = delegate(int x, int y)
            {
                return x * y;
            };
            Console.WriteLine("乘法運算:{0}×{1}={2}", a, b, method(a, b));

            method = delegate(int x, int y)
            {
                return x / y;
            };
            Console.WriteLine("除法運算:{0}÷{1}={2}", a, b, method(a, b));

            Console.ReadKey();
        }
    }
}

反編譯生成的exe文件,你會發現編譯器自動幫你生成了4個與自定義委托類型簽名一致的方法,並且Main方法中的匿名方法變成了Lamdba表達式的形式,如圖:

 

 

3.Lamdba表達式

Lamdba表達式其實就是一種語法糖,讓你更能簡潔的編寫代碼。

其語法結構:(參數列表)=>{函數體};

用Lamdba表達式實現上述例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Lamdba表達式
{
    class Program
    {
        // 聲明一個委托類型,兩個參數均為int類型,返回值為int類型
        delegate int Calc(int a, int b);

        static void Main(string[] args)
        {
            Console.WriteLine("請輸入第一個數:");
            int a = int.Parse(Console.ReadLine());

            Console.WriteLine("請輸入第二個數:");
            int b = int.Parse(Console.ReadLine());

            // 定義一個Calc委托類型的變量
            Calc method = (x, y) => { return x + y; };
            Console.WriteLine("加法運算:{0}+{1}={2}", a, b, method(a, b));

            method = (x, y) => x - y; // 也可以這樣寫
            Console.WriteLine("減法法運算:{0}-{1}={2}", a, b, method(a, b));

            method = (x, y) => { return x * y; };
            Console.WriteLine("乘法運算:{0}×{1}={2}", a, b, method(a, b));

            method = (x, y) => { return x / y; };
            Console.WriteLine("除法運算:{0}÷{1}={2}", a, b, method(a, b));

            Console.ReadKey();
        }
    }
}

你也可以反編譯生成的exe文件,你會發現結果與匿名方法反編譯的效果一樣。

二、.Net自帶的委托類型

1.Func委托類型

Func是有返回值的泛型委托,可以沒有參數,但最多只有16個參數,並且必須要有返回值,不能為void類型。如圖:

Func<int, int, int> // 第一,二個參數為int類型,返回值為int類型
Func<string, string, bool> // 第一,二個參數string類型,返回值為bool類型
Func<int, string, decimal> // 第一個參數為int類型,第二個參數為string類型,返回值為decimal類型

 

同自定義的委托類型一樣,你可以為Func委托變量賦值為方法引用,匿名方法或者Lamdba表達式:

(1)方法引用

 

(2)匿名方法

 

(3)Lamdba表達式

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Func委托類型
{
    class Program
    {
        static int Add(int a, int b)
        {
            return a + b;
        }

        static void Main(string[] args)
        {
            //Func<int, int, int> method = Add;
            //Func<int, int, int> method = delegate(int a, int b) { return a + b; };

            Func<int, int, int> method = (x, y) => { return x + y; };
            
            Console.WriteLine("加法運算:{0}+{1}={2}", 3, 4, method(3, 4));
            Console.ReadKey();
        }
    }
}

2.Action委托類型
Action是沒有返回值的泛型委托,可以沒有參數,但最多只有16個參數,返回值為void類型。如圖:

直接看例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Action委托類型
{
    class Program
    {
        static void Main(string[] args)
        {
            Action<string, string> method = (s1, s2) => { Console.WriteLine(s1 + s2); };
            
            method("1+1=", "2");
            Console.ReadKey();
        }
    }
}

3.Predicate委托類型
Predicate是只有一個參數,且返回值為bool類型的泛型委托。

// 摘要:
//     表示定義一組條件並確定指定對象是否符合這些條件的方法。
//
// 參數:
//   obj:
//     要按照由此委托表示的方法中定義的條件進行比較的對象。
//
// 類型參數:
//   T:
//     要比較的對象的類型。
//
// 返回結果:
//     如果 obj 符合由此委托表示的方法中定義的條件,則為 true;否則為 false。
public delegate bool Predicate<in T>(T obj);

 

直接看例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Predicate委托類型
{
    class Program
    {
        static void Main(string[] args)
        {
            Predicate<int> method = (x) => { return x > 3; };

            Console.WriteLine(method(4));// 輸出:True
            Console.ReadKey();
        }
    }
}


三、綜合應用

這些自帶的委托類型在泛型集合中使用的比較多,如:

 

接下來再看一個綜合例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 運用
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Student> list = new List<Student> 
            {
                new Student{Name="張三",Age=24},
                new Student{Name="李四",Age=32},
                new Student{Name="王五",Age=36},
                new Student{Name="馬六",Age=45},
                new Student{Name="李七",Age=28}
            };

            // Func委托類型
            List<Student> list2 = list.Where(item => item.Age < 30).ToList();
            foreach (Student stu in list2)
            {
                Console.WriteLine("姓名:{0},年齡:{1}。", stu.Name, stu.Age);
            }
            Console.WriteLine("============================");

            // Action委托類型
            list.ForEach((s) => { Console.WriteLine("姓名:{0},年齡:{1}。", s.Name, s.Age); });
            Console.WriteLine("============================");

            // Predicate委托類型
            Student student = list.Find(item => item.Age > 40);
            Console.WriteLine("姓名:{0},年齡:{1}。", student.Name, student.Age);
            Console.WriteLine("============================");

            Console.ReadKey();
        }
    }

    class Student
    {
        public string Name { get; set; }

        public int Age { get; set; }
    }
}
View Code

運行結果:

 


免責聲明!

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



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