委托,事件和Lambda表達式


委托

委托是什么?

委托是一種引用類型(其實就是一個類,繼承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();
        }
    }
}

參考


免責聲明!

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



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