Delegate trong C# – Ủy nhiệm hàm, tham chiếu tới phương thức | Tự học ICT

Nếu từng học C / C + +, có lẽ rằng bạn đã nghe tới khái niệm con trỏ hàm. Trong C # cũng có một công cụ với công dụng tương tự như : delegate .Nếu không biết đến con trỏ hàm, hãy tưởng tượng trường hợp khác : Khi kiến thiết xây dựng class cho người khác sử dụng bạn cần gọi một phương pháp để tính hiệu quả nhưng không biết người dùng thích đo lường và thống kê kiểu gì .Những trường hợp tương tự dẫn đến nhu yếu về một kiểu tài liệu đặc biệt quan trọng trong C # : kiểu delegate .

Nếu bạn chưa từng nghe hoặc chưa hiểu đầy đủ về delegate, bạn đã bỏ sót một công cụ rất mạnh giúp class uyển chuyển hơn. Nhiều feature trong C# như cơ chế xử lý sự kiện (trong windows forms hoặc WPF) hay LINQ hoạt động dựa trên delegate.

Nếu bạn chưa biết gì về delegate, hoặc còn đang biết mập mờ, bài viết này sẽ dành cho bạn .Bài viết sẽ cung ứng cho bạn những thông tin khá đầy đủ nhất về delegate trong C #, bảo vệ lần sau gặp lại nó bạn sẽ không còn lăn tăn gì nữa .

Delegate là gì ? Tại sao trong C # lại cần delegate

Để hiểu kiểu tài liệu này, hãy cùng xem 1 số ít trường hợp sau .Giả sử tất cả chúng ta cần kiến thiết xây dựng một class, trong class này sẽ phải gọi một phương pháp để triển khai một hành vi nào đó. Tuy nhiên tất cả chúng ta lại không biết được phương pháp này khi kiến thiết xây dựng class ! Phương thức này chỉ Open khi người khác sử dụng class để khởi tạo object .Bạn đã từng đụng chạm vào windows forms hay wpf chưa ? Nếu có chắc bạn sẽ chú ý, nút bấm ( Button ) là một class đã kiến thiết xây dựng sẵn, còn phương pháp xử lý sự kiện bấm nút ( OnClick ) lại do bạn tự viết. Làm sao để người kiến thiết xây dựng class Button biết và chạy phương pháp xử lý sự kiện do bạn viết ra ?

Vậy phải làm thế nào để hoàn thành yêu cầu “gọi một phương thức khi phương thức chưa tồn tại hoặc chưa xác định” ở giai đoạn xây dựng class?

Những trường hợp khi không biết trước được phải gọi một phương pháp đơn cử nào dẫn đến việc phải sử dụng một loại công cụ đặc biệt quan trọng trong C # : delegate .

Delegate là những kiểu dữ liệu trong C# mà biến tạo ra từ nó chứa tham chiếu tới phương thức, thay vì chứa giá trị hoặc chứa tham chiếu tới object của các class bình thường.

Thuật ngữ “delegate” dịch sang tiếng Việt có thể là kiểu đại diện hoặc kiểu ủy nhiệm. Tuy nhiên, hai lối dịch này không được sử dụng phổ biến trong các tài liệu. Vì vậy, trong bài viết này chúng ta sẽ sử dụng thuật ngữ gốc tiếng Anh – delegate.

Một biến được tạo ra từ một kiểu delegate được gọi là một biến delegate .Mỗi kiểu delegate khi được định nghĩa chỉ cho phép biến của nó chứa tham chiếu tới những phương pháp tương thích với lao lý của delegate này .

Vai trò của delegate trong C #

Delegate được cho phép một class uyển chuyển và linh động hơn trong việc sử dụng phương pháp. Theo đó, nội dung đơn cử của một phương pháp không được định nghĩa sẵn trong class mà sẽ do người dùng class đó tự định nghĩa trong quy trình khởi tạo object. Điều này giúp phân loại logic của một class ra những phần khác nhau và do những người khác nhau thiết kế xây dựng .Delegate được sử dụng để giúp một class object tương tác ngược trở lại với thực thể tạo ra và sử dụng class đó. Điều này giúp class không bị “ cô lập ” bên trong thực thể đó. Ví dụ, delegate giúp gọi những phương pháp của thực tiễn tạo ra và chứa class object .Với năng lực tạo ra tương tác ngược như vậy, delegate trở thành hạt nhân của quy mô lập trình hướng sự kiện, được sử dụng trong công nghệ tiên tiến winforms và WPF .Ví dụ, khi thiết kế xây dựng những tinh chỉnh và điều khiển của windows form ( nút bấm, nút chọn, menu, v.v. ), người lập trình ra những lớp này không hề xác lập được người dùng muốn làm gì khi nút được bấm, khi menu được chọn. Do đó, bắt buộc phải sử dụng chính sách của delegate để chuyển logic này sang cho người sử dụng những lớp đó viết code. Như vậy, Button khi được tạo ra trong một Form có năng lực tương tác với code của Form, chứ không cô lập chính mình .Delegate cũng được sử dụng thông dụng với quy mô lập trình bất đồng bộ ở dạng những phương pháp callback, hoặc trong lập trình đa luồng .

Ví dụ minh họa

Hãy thực thi và nghiên cứu và phân tích ví dụ sau để thấy rõ hơn cách khai báo và sử dụng delegate trong C # .Trong ví dụ này tất cả chúng ta “ giả lập ” một chương trình giúp đo lường và thống kê và vẽ đồ thị hàm số ( vẽ giả thôi, không phải vẽ thật đâu ). Trong đó tất cả chúng ta sẽ viết một class giúp đo lường và thống kê và in giá trị của hàm số trong một dải giá trị. Hàm số thật sự sẽ do người dùng class tự tạo và cung ứng sau .

using System;
namespace ConsoleApp
{
    /* khai báo kiểu delegate MathFunction:
     * kiểu này có mô tả là (double) -> double
     * nghĩa là có thể gán bất kỳ hàm nào "nhận biến kiểu double,
     * trả về kiểu double" cho biến thuộc kiểu MathFunction
     */
    internal delegate double MathFunction(double x);
    // giả lập việc vẽ đồ thị hàm số
    internal class Graph
    {
        /* khai báo property thuộc kiểu MathFunction.
         * MathFunction được sử dụng như những kiểu dữ liệu thông thường
         */
        public MathFunction Function { get; set; }
        /* phương thức này có 1 tham số đầu vào là kiểu delegate MathFunction.
         * Kiểu delegate làm tham số không khác gì kiểu dữ liệu bình thường
         */
        public void Render(MathFunction function, double[] range)
        {
            // có thể gán biến thuộc kiểu delegate như bình thường
            Function = function;
            // vì function là một object bình thường, nó cũng có những thuộc tính
            // và phương thức như các object khác. Thực tế tất cả kiểu delegate đều
            // kế thừa thừa lớp System.Delegate. Ở đây đang dùng thuộc tính Method 
            // của lớp này.
            Console.WriteLine($"Drawing the function graph: {function.Method}");
            foreach (var x in range)
            {
                // mặc dù function là một object nhưng có thể "gọi" như gọi hàm.
                // đây là sự khác biệt giữa object thuộc kiểu delegate với object
                // tạo ra từ class bình thường
                var y = function(x);
                // ngoài cách gọi này còn còn thể dùng cấu trúc dưới đây
                // var y = function.Invoke(x);
                // 
                // var y = function?.Invoke(x);
                Console.Write($"{y:f3}  ");
            }
            Console.WriteLine("rn-----------------");
        }
    }
    // một lớp thử nghiệm chứa các phương thức có mô tả (double)->double
    internal class Mathematics
    {
        // đây là một instance method
        public double Cos(double x) => Math.Cos(x);
        // đây là một static method
        public static double Tan(double x) => Math.Tan(x);
    }
    internal class Program
    {
        // một static method khác
        private static double Sin(double x)
        {
            return Math.Sin(x);
        }
        private static void Main(string[] args)
        {
            Graph graph = new Graph();
            // khởi tạo vùng giá trị của x
            double[] range = new double[] { 1.0, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0 };
            // truyền hàm Sin làm tham số cho Render
            graph.Render(Sin, range);
            // truyền hàm static Tan cho Render
            graph.Render(Mathematics.Tan, range);
            // truyền hàm instance Cos cho Render
            Mathematics math = new Mathematics();
            graph.Render(math.Cos, range);
            // truyền một hàm có sẵn Sqrt của lớp Math trong .net
            graph.Render(Math.Sqrt, range);
            // tạo một hàm vô danh tuân theo mô tả (double) -> double
            // và gán nó cho biến function
            // biến function là biến thuộc kiểu delegate MathFunction
            MathFunction function = delegate (double x) { return x *= 2; };
            // truyền biến function cho hàm Render
            graph.Render(function, range);
            // khai báo và truyền hàm vô danh trực tiếp tại vị trí tham số
            graph.Render(delegate (double x) { return x++; }, range);
            // khai báo và truyền hàm lambda trực tiếp tại vị trí tham số
            graph.Render((double x) => { return x *= 10; }, range);
            // truyền một hàm lambda rút gọn làm tham số
            graph.Render(x => x / 10, range);
            Console.ReadKey();
        }
    }
}

Kỹ thuật lập trình với delegate trong C #

Trong phần này tất cả chúng ta sẽ nghiên cứu và phân tích chi tiết cụ thể kỹ thuật sử dụng delegate đã gặp trong ví dụ minh họa trên .

Khai báo kiểu delegate

Trong ví dụ trên, tất cả chúng ta khai báo một kiểu delegate tên là MathFunction trực tiếp trong khoảng trống tên .

internal delegate void MathFunction(); 

Vì kiểu delegate có cùng Lever với class, nó hoàn toàn có thể được khai báo trực tiếp trong khoảng trống tên, cũng như hoàn toàn có thể khai báo làm một kiểu nội bộ bên trong class ( giống như khai báo class bên trong class ) .

Kiểu MathFunction này có hình thức tương tự với một phương thức nhận một biến kiểu double và trả lại một giá trị double.

Qua đây chúng ta thấy, về mặt hình thức, khai báo một kiểu delegate giống như khai báo một phương thức không có thân, chỉ cần thêm từ khóa delegate trước kiểu trả về và kết thúc khai báo bằng dấu chấm phẩy.

Mô tả phương pháp và delegate

Để thuận tiện hơn trong việc diễn đạt phương pháp ( và kiểu delegate ), người ta đưa ra một quy ước miêu tả như sau : ( list tham số theo kiểu ) -> kiểu đầu ra. Ví dụ, phương pháp

private float Div(int a, int b){} 

có miêu tả là ( int, int ) -> float .Khi đọc diễn đạt này tất cả chúng ta sẽ hiểu : phương pháp ( không chăm sóc đến tên gọi ) có hai tham số đầu vào cùng kiểu int và trả về tác dụng thuộc kiểu float .

Với quy ước viết này, MathFunction ở trên đại diện cho tất cả các phương thước có mô tả là (double) -> double.

Tất cả các phương thức có mô tả (double)->double đều có thể gán cho biến thuộc kiểu MathFunction. Mô tả này cũng được gọi là mô tả của MathFunction.

Khai báo và sử dụng biến delegate

Sau khi khai báo kiểu, hoàn toàn có thể khai báo biến thuộc kiểu tài liệu này tương tự như như khai báo những biến thông thường :

/* khai báo property thuộc kiểu MathFunction.
 * MathFunction được sử dụng như những kiểu dữ liệu thông thường
 */
public MathFunction Function { get; set; }

Tham số thuộc kiểu delegate hoàn toàn có thể được khai báo và gán như tham số thông thường :

/* phương thức này có 1 tham số đầu vào là kiểu delegate MathFunction.
 * Kiểu delegate làm tham số không khác gì kiểu dữ liệu bình thường
 */        
public void Render(MathFunction function, double[] range)
{
    // có thể gán biến thuộc kiểu delegate như bình thường
    Function = function;

Biến thuộc kiểu delegate cũng là một object, tương tự như các object tạo ra từ class, nó cũng có thuộc tính và phương thức như các object bình thường. Thực tế, tất cả kiểu delegate do người dùng định nghĩa đều kế thừa từ lớp System.Delegate nên cũng được kế thừa các thuộc tính và phương thức của class này.

Bởi vì biến delegate sẽ chứa tham chiếu tới một phương pháp, ta hoàn toàn có thể sử dụng tên biến delegate như một phương pháp thực thụ, nghĩa là hoàn toàn có thể “ gọi ” biến này như gọi phương pháp thông thường. Khi “ gọi ” một biến delegate, phương pháp nó trỏ tới sẽ được thực thi .

// vì function là một object bình thường, nó cũng có những thuộc tính
            // và phương thức như các object khác. Thực tế tất cả kiểu delegate đều
            // kế thừa thừa lớp System.Delegate. Ở đây đang dùng thuộc tính Method 
            // của lớp này.
            Console.WriteLine($"Drawing the function graph: {function.Method}");
            foreach (var x in range)
            {
                // mặc dù function là một object nhưng có thể "gọi" như gọi hàm.
                // đây là sự khác biệt giữa object thuộc kiểu delegate với object
                // tạo ra từ class bình thường
                var y = function(x);
                // ngoài cách gọi này còn còn thể dùng cấu trúc dưới đây
                // var y = function.Invoke(x);
                // kiểm tra biến delegate trước khi gọi để tránh lỗi
                // var y = function?.Invoke(x);
                Console.Write($"{y:f3}  ");
            }

Ngoài cách “gọi” biến delegate như gọi phương thức, các kiểu delegate còn có thêm phương thức Invoke giúp gọi phương thức biến này trỏ tới:

var y = function.Invoke(x); 

Cẩn thận hơn nữa tất cả chúng ta hoàn toàn có thể kiểm tra object trước khi gọi Invoke :

var y = function?.Invoke(x); 

Phép toán ? được cho phép kiểm tra xem một object function có giá trị null hay không. Nếu object nhận giá trị khác null mới thực thi phương pháp Invoke. Cách sử dụng này là bảo đảm an toàn nhất. Nếu function nhận giá trị null thì phương pháp Invoke sẽ không được gọi. Nếu không kiểm tra null, lời gọi phương pháp trên một object null sẽ làm phát sinh lỗi .

Truyền tham số kiểu delegate cho phương pháp

Ở tiến trình khởi tạo object của class, người dùng class mới truyền phương pháp đơn cử cho tham số thuộc kiểu delegate .

// truyền hàm Sin làm tham số cho Render
graph.Render(Sin, range);
// truyền hàm static Tan cho Render
graph.Render(Mathematics.Tan, range);
// truyền hàm instance Cos cho Render
Mathematics math = new Mathematics();
graph.Render(math.Cos, range);
// truyền một hàm có sẵn Sqrt của lớp Math trong .net
graph.Render(Math.Sqrt, range);

Nếu một tham số của phương pháp là biến delegate, tất cả chúng ta hoàn toàn có thể trực tiếp truyền tên của một phương pháp có chung diễn đạt với kiểu delegate .Lưu ý : truyền một phương pháp làm tham số khác với truyền lời gọi phương pháp làm tham số. Truyền lời gọi phương pháp hoàn toàn có thể xem như tương tự với truyền tài liệu thông thường ( string, bool, int, v.v. ), không tương quan đến delegate .

Generic delegate

Như đã biết khi xem xét về delegate, để thao tác với delegate tất cả chúng ta cần trước hết khai báo delegate như khai báo kiểu tài liệu thông thường, sau đó sử dụng kiểu delegate đó để khai báo biến. Đến tiến trình sử dụng tất cả chúng ta gán biến delegate đó với một phương pháp tương thích với nhu yếu của kiểu delegate .C # tương hỗ người lập trình bằng cách định nghĩa ra một loạt kiểu tài liệu generic delegate mà tất cả chúng ta hoàn toàn có thể trực tiếp sử dụng ngay để khai báo biến. Sử dụng generic delegate giúp bỏ lỡ tiến trình khai báo kiểu delegate .Đọc bài viết này để nắm rõ hơn về generic trong C # .Về cơ bản, generic delegate là những kiểu delegate đã được định nghĩa sẵn sử dụng chính sách generic. . NET framework định nghĩa 3 nhóm generic delegate : Actions, Funcs, Predicates .

Actions

Actions là những kiểu delegate tương ứng với những phương pháp không trả về tài liệu ( đầu ra là void ). Các kiểu kích hoạt được định nghĩa trong khoảng trống tên System như sau :

namespace System
{
    public delegate void Action();
    public delegate void Action(T obj);
    public delegate void Action(T1 arg1, T2 arg2);
    // còn các delegate tương tự như vậy nữa
    // .NET framework định nghĩa tổng cộng 16 delegate như vậy với số lượng tham số đầu vào từ 1 đến 16.
}

. NET framework định nghĩa tổng số 16 generic delegate, cái tiên phong có 1 tham số nguồn vào, cái sau cuối có 16 tham số nguồn vào .

Như vậy, kiểu Action có thể tương ứng với bất kỳ phương thức nào không trả về giá trị và có từ 1 đến 16 tham số đầu vào (bất kỳ kiểu gì). Riêng delegate void Action() tương ứng với các phương thức không nhận tham số và không trả về giá trị.

Như vậy, khi sử dụng Action hoặc Action sẽ không cần khai báo các kiểu delegate có kiểu ra là void nữa (và có ít hơn 16 tham số đầu vào).

Dưới đây là một số ít ví dụ về cách sử dụng những kiểu actions :

Action action1 = () => Console.WriteLine("Hello world");
Action action2 = (s) => Console.WriteLine(s);
Action action3 = (s, i) => { for (int j = 0; j < i; j++) Console.WriteLine(s); };

Funcs

Funcs là những kiểu delegate tương ứng với những phương pháp có trả về tài liệu. Các kiểu funcs được định nghĩa trong khoảng trống tên System như sau :

namespace System
{
    public delegate TResult Func();
    public delegate TResult Func(T arg);
    public delegate TResult Func(T1 arg1, T2 arg2);
    // có 17 delegate tương tự như vậy
}

Tương tự như với actions ,. NET framework cũng định nghĩa 17 kiểu delegate như trên với số lượng tham số đầu vào từ 0 đến 16 .Định nghĩa kiểu funcs khác với actions ở chỗ, funcs luôn phải có kiểu đầu ra đặt ở vị trí sau cuối trong list kiểu giả generic ( out TResult ). Sau đây là 1 số ít ví dụ sử dụng funcs :

Func func1 = () => 0;
Func func2 = (i) => i * 10;
Func func3 = (a, b) => a / b;
Console.WriteLine($"func1: {func1}; func2: {func2(10)}; func3: {func3(1, 2)}");

Biến func1 được khai báo và tham chiếu tới hàm lambda không nhận tham số và luôn trả về giá trị 0 ( kiểu int ) ; biến func2 tham chiếu tới hàm lambda nhận tham số vào kiểu int, nhân tham số đó với 10 và trả lại tác dụng này ( kiểu int ) ; biến func3 tham chiếu tới hàm lambda nhận hai số nguyên và trả về tác dụng phép chia ( kiểu float ) .

Predicate

Predicate là kiểu delegate được định nghĩa sẵn như sau ( trong System ) :

namespace System
{    
    public delegate bool Predicate<[NullableAttribute(2)] in T>(T obj);
}

Như vậy, predicate là kiểu delegate tương ứng với những phương pháp có 1 tham số đầu vào và trả về giá trị bool. Predicate được sử dụng trong những biểu thức so sánh. Dưới đây là 1 số ít ví dụ :

Predicate predicate1 = (i) => i > 100;
Console.WriteLine($"is 10 > 100? it's {predicate1(10)}");
Predicate predicate2 = (s) => s.Length > 10;

Biến predicate1 tham chiếu tới một hàm lambda triển khai so sánh xem một số ít nguyên có lớn hơn 100 hay không ; biến predicate2 tham chiếu tới một hàm lambda nhận một chuỗi ký tự và so sánh xem độ dài chuỗi đó có lớn hơn 10 không .Như tất cả chúng ta thấy trong những ví dụ trên đều sử dụng hàm lambda với delegate. Khi sử dụng theo kiểu này tất cả chúng ta hoàn toàn có thể trọn vẹn bỏ lỡ việc khai báo kiểu của tham số trong hàm lambda vì C # hoàn toàn có thể tự suy đoán ra kiểu. Ngoài ra, nếu thân phương pháp chỉ có 1 lệnh duy nhất thì sử dụng lối viết “ expression body toàn thân ” cho gọn .

Sử dụng delegate với phương pháp vô danh, hàm lambda, hàm cục bộ

Để truyền tham số thuộc kiểu delegate cho một phương pháp, tất cả chúng ta phải viết những phương pháp có diễn đạt mà kiểu delegate nhu yếu .Do đặc trưng của C #, phương pháp bắt buộc phải được định nghĩa trong một class ( dù là instance method hay static method ). Đối với instance method, tất cả chúng ta còn phải khởi tạo object trước khi truyền phương pháp này làm tham số cho phương pháp khác qua delegate .Nếu phương pháp này chỉ được sử dụng một lần duy nhất lúc truyền làm tham số, hoặc phương pháp quá đơn thuần ( chỉ gồm có 1 dòng lệnh ), việc kiến thiết xây dựng hàng loạt phương pháp nhỏ như vậy hoàn toàn có thể làm code bị phân mảnh khiến khó theo dõi và quản trị .C # 2 mở màn đưa vào khái niệm phương pháp vô danh ( anonymous method ), C # 3 đưa vào khái niệm hàm lambda ( lambda statement ) giúp thiết kế xây dựng những phương pháp sử dụng một lần như vậy. Hiện nay hàm lambda được sử dụng phổ cập hơn .

Phương thức vô danh

Phương thức vô danh ( anonymous method ) cũng là một loại phương pháp, tuy nhiên độc lạ với phương pháp thông thường ở một số ít điểm :

  1. Không có tên: vì phương thức vô danh chủ yếu được sử dụng làm tham số cho phương thức khác, điều quan trọng nhất là hoạt động của phương thức (thân phương thức), còn tên không quan trọng; phương thức loại này cũng không được gọi lại (tái sử dụng) ở nhiều nơi trong code như phương thức bình thường, do đó cũng không cần tên gọi.
  2. Có thể khai báo trực tiếp ở chỗ cần dùng: ví dụ có thể khai báo thẳng trong danh sách tham số của hàm khác, và do đó, có thể truy xuất cả các biến cục bộ của phương thức nơi nó được khai báo.

Trong các tài liệu có thể sử dụng hai cách gọi: phương thức vô danh hoặc phương thức nặc danh. Hai cách gọi này là tương đương. Trong bài giảng này chúng ta thống nhất gọi là phương thức vô danh.

Hãy cùng xem ví dụ sau đây về khai báo phương pháp vô danh :

Chúng ta vẫn tiếp tục sử dụng ví dụ minh họa đã làm ở bài trước. Ở đây chúng ta không khai báo thêm phương thức bình thường như trước mà trực tiếp khai báo một phương thức vô danh và gán cho biến function thuộc kiểu MathFunction:

// tạo một hàm vô danh tuân theo mô tả (double) -> double
// và gán nó cho biến function
// biến function là biến thuộc kiểu delegate MathFunction
MathFunction function = delegate (double x) { return x *= 2; };
// truyền biến function cho hàm Render
graph.Render(function, range);
// khai báo và truyền hàm vô danh trực tiếp tại vị trí tham số
graph.Render(delegate (double x) { return x++; }, range);

Chúng ta cũng hoàn toàn có thể khai báo phương pháp vô danh trực tiếp ở vị trí tham số :

graph.Render(delegate (double x) { return x++; }, range); 

Qua ví dụ này hoàn toàn có thể thấy, khai báo phương pháp vô danh chỉ độc lạ với phương pháp thường thì ở chỗ, vị trí tên phương pháp được thay thế sửa chữa bằng từ khóa delegate .

Hàm lambda

Hàm lambda cũng có những đặc trưng của phương pháp vô danh nhưng hoàn toàn có thể bỏ lỡ luôn khai báo kiểu của những tham số .Điều này xuất phát từ thực tiễn là hàm lambda khi được khai báo làm tham số của một phương pháp thì những tham số của nó bắt buộc phải tuân thủ theo miêu tả của delegate. Do đó C # compiler hoàn toàn có thể tự suy ra kiểu của những tham số mà không cần viết rõ ra .Tương tự, một hàm lambda được khai báo trọn vẹn giống như một phương pháp thông thường, độc lạ lớn nhất là nó hoàn toàn có thể được khai báo thẳng trong thân phương pháp khác ( giống phương pháp vô danh ), và list tham số được nối với thân phương pháp bằng dấu =>. Phương thức lambda cũng rất thường được sử dụng với expression body toàn thân .

// khai báo và truyền hàm lambda trực tiếp tại vị trí tham số
graph.Render((double x) => { return x *= 10; }, range);
// truyền một hàm lambda rút gọn làm tham số
graph.Render(x => x / 10, range);

Ở trường hợp thứ hai tất cả chúng ta thấy list tham số của hàm lambda thậm chí còn không có cả tên kiểu tài liệu .Lý do là vì hàm này dùng làm tham số thứ nhất cho phương pháp Render. Tham số này đã được lao lý miêu tả là ( double ) -> double. Do đó, tham số x sẽ được C # tự hiểu là thuộc kiểu double. Khả năng tự suy đoán kiểu này tích hợp với expression body toàn thân giúp hàm lambda trở nên rất ngắn gọn .Hãy cùng xem hiệu quả triển khai của chương trình ví dụ trên :Kết quả thực hiện chương trìnhKết quả thực hiện chương trìnhỞ những vị trí tất cả chúng ta truyền phương pháp vô danh và hàm lambda, C # compiler tự sinh ra tên gọi cho những hàm này. Tuy nhiên, vì lúc code không có tên, tất cả chúng ta không có năng lực gọi lại những hàm này ở những vị trí khác trong code .

Hàm cục bộ

Từ C # 7, tất cả chúng ta có thêm một năng lực nữa để thiết kế xây dựng một phương pháp trong thân một phương pháp khác bên cạnh sử dụng phương pháp vô danh và hàm lambda : sử dụng hàm cục bộ ( local function ) .Hàm cục bộ là một phương pháp được định nghĩa bên trong thân một phương pháp khác .Hàm cục bộ trọn vẹn không độc lạ với những phương pháp thường thì. Tuy nhiên hàm cục bộ không có từ khóa điều khiển và tinh chỉnh truy vấn và chỉ hoàn toàn có thể được gọi bên trong thân phương pháp chứa nó .Nếu bạn chưa biết : trong C # có hai điều độc lạ với nhiều ngôn từ khác thuộc họ C / C + + : ( 1 ) hoàn toàn có thể khai báo class bên trong class, và ( 2 ) hoàn toàn có thể khai báo phương pháp bên trong phương pháp .

Kết luận

Đến đây chúng ta đã kết thúc một bài viết dài và tương đối đầy đủ về delegate trong C#. Như bạn đã thấy, delegate cũng là một khái niệm vô cùng quan trọng trong C# mà bạn không thể không biết.

Hi vọng bài viết này sẽ giúp ích cho bạn .Chúc bạn học tốt !

+ Nếu bạn thấy site hữu ích, trước khi rời đi hãy giúp đỡ site bằng một hành động nhỏ để site có thể phát triển và phục vụ bạn tốt hơn.
+ Nếu bạn thấy bài viết hữu ích, hãy giúp chia sẻ tới mọi người.
+ Nếu có thắc mắc hoặc cần trao đổi thêm, mời bạn viết trong phần thảo luận cuối trang.
Cảm ơn bạn!