自訂委派
若要透過委派執行某個方法,通常就必須先宣告一個委派結構。我們先來回顧一下,如何叫用自訂委派
具名委派
//宣告一個委派結構 public delegate bool CustomDelegate(Employee emp); private Boolean IsAdult(Employee emp) { return emp.Age >= 20; } private void button1_Click(object sender, EventArgs e) { List<Employee> Employees = GetEmployeeList(); //自訂具名委派 CustomDelegate cusDelegate1 = IsAdult; foreach (Employee emp in Employees) Console.WriteLine(cusDelegate1(emp)); }
匿名委派
上面例子中,當建立委派的執行個體時,也就是委派在具現化(Instantiated)時,會與要叫用的方法建立關聯,這做法就是具名委派。 C# 也允許在具現化時,直接使用 Lambda 運算式或匿名方法,將要執行的程式碼區塊直接連接在宣告定義中,這做法就是匿名委派。 所以上面例子,可以改寫成使用以下的匿名委派做法。
//宣告一個委派結構 public delegate bool CustomDelegate(Employee emp); private void button1_Click(object sender, EventArgs e) { List<Employee> Employees = GetEmployeeList(); //自訂匿名委派 CustomDelegate cusDelegate2 = emp => emp.Age >= 20; foreach (Employee emp in Employees) Console.WriteLine(cusDelegate2(emp)); }
自訂泛型委派
我們也可以將以上用法,改成使用泛型宣告。
具名委派
//宣告一個委派結構 public delegate bool CustomGenDelegate<T>(T item); private bool IsAdult(Employee emp) { return emp.Age >= 20; } private void button1_Click(object sender, EventArgs e) { List<Employee> Employees = GetEmployeeList(); //自訂泛型具名委派 CustomGenDelegate<Employee> cusgenDelegate1 = IsAdult; foreach (Employee emp in Employees) Console.WriteLine(cusgenDelegate1(emp)); }
匿名委派
上面例子,我們可以改寫成使用匿名委派。
//宣告一個委派結構 public delegate bool CustomGenDelegate<T>(T item); private void button1_Click(object sender, EventArgs e) { List<Employee> Employees = GetEmployeeList(); //自訂泛型匿名委派 CustomGenDelegate <Employee> cusgenDelegate2 = emp => emp.Age >= 20; foreach (Employee emp in Employees) Console.WriteLine(cusgenDelegate2(emp)); }
我們再上面例子改寫成連委派的回傳值都是泛型。
宣告一個泛型委派結構 public delegate R CustomGenericDelegate<in T, out R>(T item); private void button2_Click(object sender, EventArgs e) { List<Employee> Employees = GetEmployeeList(); CustomGenericDelegate<Employee, bool> cusgenDelegate4 = emp => emp.Age >= 20; foreach (Employee emp in Employees) Console.WriteLine(cusgenDelegate4(emp)); }
Func委派、Action委派、Predicate委派
.NET 底下的 Func<T> 和 Action<T> 到底是什麼?我們先看看它的宣告:
public delegate TResult Func<out TResult>(); public delegate TResult Func<in T, out TResult>(T arg) public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2) public delegate TResult Func<in T1, in T2, in T3, out TResult>(T1 arg1, T2 arg2, T3 arg3) ... public delegate void Action<in T>(T obj); public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2); public delegate void Action<in T1, in T2, in T3>(T1 arg1, T2 arg2, T2 arg3); ... public delegate bool Predicate<in T>(T obj)
比較一下上面宣告中的第二行的 Func 宣告,是不是和前一個例子的自訂泛型委派是一樣的。 沒錯,上面這些長的怪怪的宣告,只不過是 .NET 系統內建的泛型委派結構罷了,沒什麼特別的,以後不要再害怕看到它了。 補充幾點:
- Func 和 Action 的差異只在於是否有回傳值。
- Predicate 只是 Func 中的一個特例,就是相當於 Func<T, bool> ,也就是只帶一個參數,並回傳 bool 型態。
- .NET 2.0只支援0~1個參數的泛型委派。
- .NET 3.5支援0~4個參數的泛型委派。
- .NET 4.0支援0~16個參數的泛型委派。
因此,若要使用系統內建的泛型委派,上面例子可以改寫如下:
List<Employee> Employees = GetEmployeeList(); //使用 Func<T> 泛型委派 + 具名方法 Func<Employee, bool> genDelegate1 = IsAdult; foreach (Employee emp in Employees) Console.WriteLine(genDelegate1(emp)); //使用 Func<T> 泛型委派 + 匿名方法 Func<Employee, bool> genDelegate2 = delegate(Employee emp) { return emp.Age >= 20; }; //使用 Func<T> 泛型委派 + 匿名方法 Func<Employee, bool> genDelegate2 = emp => emp.Age >= 20; foreach (Employee emp in Employees) Console.WriteLine(genDelegate2(emp)); //使用 Predicate<T> 泛型委派 + 具名方法 Predicate<Employee> genDelegate3 = IsAdult; foreach (Employee emp in Employees) Console.WriteLine(genDelegate3(emp)); //使用 Predicate<T> 泛型委派 + 匿名方法 Predicate<Employee> genDelegate4 = emp => emp.Age >= 20; foreach (Employee emp in Employees) Console.WriteLine(genDelegate4(emp));
泛型方法
泛型方法:帶有泛型參數的方法,如下所示:。
public void SwapGen<T>(ref T x, ref T y) { T tmp; tmp = x; x = y; y = tmp; }
叫用泛型方法:
string x = "12"; string y = "34"; SwapGen<string>(ref x, ref y); SwapGen(ref x, ref y); //可省略型別引數,編譯器會自行推斷
類別中的泛型方法:
public class MyClassA { public void SwapGen<T>(ref T x, ref T y) { T tmp; tmp = x; x = y; y = tmp; } }
如果把泛型參數定義在類別上,非泛型方法也可以存取該類別層級中的泛型參數,如下所示:
public class MyClassA<T> { public void SwapGen(ref T x, ref T y) { T tmp; tmp = x; x = y; y = tmp; } }
泛型類別
泛型類別:類別定義中,包含非特定型別的封裝。
public class MyClassA<T> { //T 類別中會使用到的某個型別,這個型別由程式碼在具現化時才決定。 } MyClassA<string> class1 = new MyClassA<string>(); MyClassA<int> class2 = new MyClassA<int>();
泛型類別常應用於與集合(Collection)相關的物件中,例如:stacks, queues, lists 等等。 這類物件的操作方法基本上都是相同的,只是資料項目的型別不同罷了。
Dictionary<TKey, TValue> 類別
表示索引鍵和值的集合。
Dictionary<TKey, TValue>() //這個建構子會使用索引鍵型別的預設相等比較子。 Dictionary<TKey, TValue>(Int32) //建立具有指定初始容量的集合,這個建構子也是使用索引鍵型別的預設相等比較子。 Dictionary<TKey, TValue>(IEqualityComparer<TKey>) //這個建構子會使用指定的 IEqualityComparer<T> 當做比較子。
Task 類別 & Task<TResult> 類別
Task<TResult> 表示一個非同步的作業,並且會回傳值。
1) Task(Action):使用指定的 Action,初始化新的 Task。 2) Task(Action<Object>, Object):使用指定的Action和State,初始化新的 Task。 3) Task(Action, CancellationToken):使用指定的Action和CancellationToken(取消憑證),初始化新的 Task。
1) Task<TResult>(Func<TResult>) //使用指定的函式,初始化新的 Task<TResult>。 2) Task<TResult>(Func<TResult>, CancellationToken) //使用指定的函式和取消作業參數,初始化新的 Task<TResult>。 3) Task<TResult>(Func<Object, TResult>, Object) //使用指定的函式和建立選項,初始化新的 Task<TResult>。 ...
Task<TResult>(Func<TResult>) 什麼意思
- 類別中會使用到一個非特定型別(TResult)。
- 具現化時,必須使用函式名稱當做參數。
- 該函式名稱必須回傳(TResult)型別的值。
private AtomEntry UploadFile() { return UploadFileAsync(gsAlubmId, @"01.jpg"); //return AtomEntry; } private void bnTaskResult_Click(object sender, EventArgs e) { // Task<TResult>(Func<TResult>) Task<AtomEntry> task1 = new Task<AtomEntry>(UploadFile1); }
Task<TResult>(Func<Object, TResult>, Object) 什麼意思
- 類別中會使用到一個非特定型別(TResult)。
- 具現化時,必須使用函式名稱當做參數。
- 該函式名稱必須傳入一個 Object 型別參數,並回傳(TResult)型別的值。
private AtomEntry UploadFile2(Object filename) { return UploadFileAsync(gsAlubmId, filename.ToString()); //return AtomEntry; } private void bnTaskResult_Click(object sender, EventArgs e) { // Task<TResult>(Func<Object, TResult>, Object) Task<AtomEntry> task2 = new Task<AtomEntry>(UploadFile2, filename); }
沒有留言:
張貼留言