委托
委托是什么?
委托是一種引用類型(其實就是一個類,繼承MulticastDelegate特殊的類。),表示對具有特定參數列表和返回類型的方法的引用。
每個委托提供Invoke方法, BeginInvoke和EndInvoke異步方法
為什么需要委托?
- 委托可以將方法(即邏輯)作為參數;
- 邏輯解耦,保持穩定。
- 代碼復用,保證項目規范。
如何使用委托?
如何聲明、實例化和使用委托
聲明委托
delegate void Del(string str);
static void Notify(string name)
{
Console.WriteLine($"Notification received for: {name}");
}
實例化委托
Del del1 = new Del(Notify);
//C# 2.0
Del del2 = Notify;
調用委托
del1.Invoke("小明");
del2("小明");
其他使用委托
//C# 2.0使用匿名方法來聲明和實例化委托
Del del3 = delegate(string name)
{ Console.WriteLine($"Notification received for: {name}"); };
//C# 3.0使用lambda表達式聲明和實例化委托
Del del4 = name => { Console.WriteLine($"Notification received for: {name}"); };
簡化開發過程,.NET 包含一組委托類型:
- Action<> 具有參數且不返回值。
- Func<> 具有參數且返回由參數指定的類型的值。
- Predicate<> 用於確定參數是否滿足委托條件的情況。
實際案例
代碼:
class Program
{
/// <summary>
/// 聲明委托
/// </summary>
/// <param name="fullName"></param>
private delegate void KillDelegate(string fullName);
static void Main(string[] args)
{
//實例化委托
var killWithKnifeDelegate = new KillDelegate(KillWithKnife);
Kill("郭靖", killWithKnifeDelegate);
var killWithSwordDelegate = new KillDelegate(KillWithSword);
Kill("黃蓉", killWithSwordDelegate);
var killWithAxeDelegate = new KillDelegate(KillWithAxe);
Kill("歐陽克", killWithAxeDelegate);
Console.ReadKey();
}
static void Kill(string fullName, KillDelegate killDelegate)
{
Console.WriteLine($"{fullName}遇到怪物");
//調用委托
killDelegate.Invoke(fullName);
Console.WriteLine($"{fullName}增長10經驗");
}
static void KillWithKnife(string fullName)
{
Console.WriteLine($"{fullName}用刀殺怪物");
}
static void KillWithSword(string fullName)
{
Console.WriteLine($"{fullName}用劍殺怪物");
}
static void KillWithAxe(string fullName)
{
Console.WriteLine($"{fullName}用斧殺怪物");
}
}
Lambda表達式
Lambda是什么?
Lambda就是使用委托的更方便的語法。
//C# 2.0使用匿名方法來聲明和實例化委托
Del del3 = delegate(string name)
{ Console.WriteLine($"Notification received for: {name}"); };
//C# 3.0使用lambda表達式聲明和實例化委托
Del del4 = name => { Console.WriteLine($"Notification received for: {name}"); };
為什么需要Lambda?
簡化開發過程,並不會影響運行性能。
如何使用Lambda?
表達式lambda基本形式:
//僅當 lambda 只有一個輸入參數時,括號才是可選的;否則括號是必需的
(input-parameters) => expression
使用空括號指定零個輸入參數:
Action line = () => Console.WriteLine();
括號內的兩個或更多輸入參數使用逗號加以分隔:
Func<int, int, bool> testForEquality = (x, y) => x == y;
語句lambda
(input-parameters) => { <sequence-of-statements> }
語句 lambda 的主體可以包含任意數量的語句;
Action<string> greet = name =>
{
string greeting = $"Hello {name}!";
Console.WriteLine(greeting);
};
greet("World");
// Output:
// Hello World!
使用匿名委托和lambda代碼:
public static void Main(string[] args)
{
List<int> list = new List<int>();
for (int i = 1; i <= 100; i++)
{
list.Add(i);
}
//使用匿名委托
List<int> result = list.FindAll(
delegate (int no)
{
return (no % 2 == 0);
}
);
foreach (var item in result)
{
Console.WriteLine(item);
}
//使用Lambda
List<int> result = list.FindAll(i => i % 2 == 0);
foreach (var item in result)
{
Console.WriteLine(item);
}
}
事件
事件是什么?
事件是一種特殊的委托類型,主要用於消息或通知的傳遞。事件只能從事件的發布類型中調用,並且通常基於EventHandler委托,該委托具有代表事件發送者的對象和System.EventArgs派生的類,其中包含有關事件的數據。
何時使用委托和事件?
- 偵聽事件是可選的:如果你的代碼必須調用由訂閱服務器提供的代碼,則應使用基於委托的設計。如果你的代碼在不調用任何訂閱服務器的情況下可完成其所有工作,則應使用基於事件的設計。
- 返回值需要委托:用於事件的委托均具有無效的返回類型,事件處理程序通過修改事件參數對象的屬性將信息傳回到事件源。
- 事件具有專用調用:包含事件的類以外的類只能添加和刪除事件偵聽器;只有包含事件的類才能調用事件。
如何使用事件?
發布事件
定義事件數據
public class CustomEventArgs : EventArgs
{
public CustomEventArgs(string message)
{
Message = message;
}
public string Message { get; set; }
}
聲明發布類中的事件
public delegate void CustomEventHandler(object sender, CustomEventArgs args);
public event CustomEventHandler RaiseCustomEvent;
//使用泛型版本
public event EventHandler<CustomEventArgs> RaiseCustomEvent;
訂閱事件
定義一個事件處理程序方法
void HandleCustomEvent(object sender, CustomEventArgs a)
{
// Do something useful here.
}
使用(+=) 添加訂閱事件
publisher.RaiseCustomEvent += HandleCustomEvent;
使用(-=) 取消訂閱事件
publisher.RaiseCustomEvent -= HandleCustomEvent;
示例
using System;
namespace DotNetEvents
{
// 定義事件信息的類
public class CustomEventArgs : EventArgs
{
public CustomEventArgs(string message)
{
Message = message;
}
public string Message { get; set; }
}
// 發布事件的類
class Publisher
{
// 使用EventHandler <T>聲明事件
public event EventHandler<CustomEventArgs> RaiseCustomEvent;
public void DoSomething()
{
RaiseCustomEvent(new CustomEventArgs("Event triggered"));
}
}
//訂閱事件的類
class Subscriber
{
private readonly string _id;
public Subscriber(string id, Publisher pub)
{
_id = id;
// 添加訂閱事件
pub.RaiseCustomEvent += HandleCustomEvent;
}
// 定義一個事件處理程序方法。
void HandleCustomEvent(object sender, CustomEventArgs e)
{
Console.WriteLine($"{_id} received this message: {e.Message}");
}
}
class Program
{
static void Main()
{
var pub = new Publisher();
var sub1 = new Subscriber("sub1", pub);
var sub2 = new Subscriber("sub2", pub);
// 調用引發事件的方法
pub.DoSomething();
Console.ReadKey();
}
}
}