Việc sử dụng C # Delegates trong thế giới thực [đã đóng]


16

Tôi nghĩ rằng về mặt khái niệm tôi hiểu các đại biểu C #, tuy nhiên, tôi đang vật lộn để tìm một ví dụ thực tế nơi họ sẽ hữu ích. Bạn có thể cung cấp một số câu trả lời chi tiết về cách các đại biểu C # được sử dụng trong các ứng dụng thực không và những vấn đề họ cho phép bạn giải quyết.


2
Hầu như mọi lớp đơn trong .NET framework đều hiển thị một số sự kiện, vì vậy bạn hãy đến đó. Nó chỉ là một cách để gói gọn một số đơn vị công việc. Ví dụ, giả sử bạn đang triển khai cấu trúc cây nhị phân chung trong C. Chà, cách duy nhất để đặt hàng cây của bạn là lấy tham số làm con trỏ hàm biết cách thực hiện sắp xếp.
Ed S.

Câu trả lời:


16

Mã GUI sử dụng các đại biểu để xử lý các sự kiện, chẳng hạn như nhấp vào nút, di chuyển cửa sổ. Sử dụng ủy nhiệm cho phép bạn có một hàm được gọi bất cứ khi nào sự kiện xảy ra. Một ví dụ sẽ liên kết một chức năng lưu dữ liệu vào nút "Lưu" trên giao diện. Khi nhấn vào nút, nó được thiết lập để thực hiện chức năng lưu dữ liệu. Nó hữu ích trong lập trình GUI vì toàn bộ chương trình của bạn có thể đang chờ người dùng làm điều gì đó và bạn không có cách nào để biết họ sẽ làm gì trước tiên. Việc sử dụng các đại biểu cho phép chức năng của chương trình của bạn được kết nối với giao diện người dùng theo cách mà người dùng có thể thực hiện mọi việc theo bất kỳ cách nào họ muốn.


2
++ Bạn nói đúng, nhưng tôi vẫn ghét nó :-) vì vậy từ lâu tôi đã nghĩ ra cái này thay thế .
Mike Dunlavey

12

Linq sử dụng Func<T>Action<T>đại biểu khắp nơi làm tham số.

Điều này cho phép bạn sử dụng biểu thức lambda làm tham số và xác định hành động sẽ được thực hiện như một phần của danh sách tham số.


12

Hầu như bất cứ điều gì sử dụng Mẫu quan sát viên đều có thể triển khai các đại biểu.

Đọc mô tả và bạn có thể sẽ tưởng tượng một số tình huống mà bạn sẽ sử dụng chúng. Xử lý sự kiện GUI là một ví dụ phổ biến.


+1, Mẫu chiến lược thực sự là nơi các đại biểu tỏa sáng, tức là bạn có một số lớp trong đó một số phương thức làm một cái gì đó, nhưng bạn muốn một cái gì đó có thể thay thế cho nhau và không phụ thuộc trực tiếp, các đại biểu ergo. Lưu ý rằng các sự kiện sẽ đáp ứng nhu cầu giống như các đại biểu, sự khác biệt là bạn sử dụng các đại biểu khi bạn cần phản ứng với một số giá trị trả về, trong khi bạn chỉ thực hiện các sự kiện và bất cứ điều gì sẽ xảy ra.
Homde

9

Các đại biểu rất hữu ích trong lập trình không đồng bộ.

Bạn có một lớp làm công cụ không đồng bộ và có một cuộc gọi lại. Bạn có thể có phương thức ủy nhiệm được gọi khi gọi lại - và việc triển khai lớp của bạn sẽ thực hiện logic được mô tả trong phương thức ủy nhiệm của bạn.


9

Các đại biểu đặc biệt hữu ích như một giải pháp cho lỗ hổng trong mẫu ở giữa . Về cơ bản, có rất nhiều trường hợp bạn muốn bọc một bộ hướng dẫn duy nhất bên trong một loạt các hướng dẫn chung. Điều này đặc biệt khó khăn nếu các hướng dẫn trước và sau bit duy nhất cần chia sẻ trạng thái. Với các đại biểu, bạn chỉ có thể chuyển một đại biểu vào một chức năng. Hàm thực thi bit trước, thực thi ủy nhiệm, sau đó thực hiện bit sau.


5

Trong "ngày xưa" của các ngôn ngữ không phải OOP như Fortran và C, thật hữu ích khi có thể có một chương trình con nhận được một đối số là con trỏ tới hàm. Ví dụ, qsorthàm hoạt động với chức năng so sánh do người dùng cung cấp. Có rất nhiều chương trình con để giải các phương trình vi phân thông thường hoặc để tối ưu hóa các hàm và tất cả chúng đều lấy các con trỏ hàm làm đối số.

Trong các hệ thống cửa sổ, tất cả các loại gọi lại theo cùng một mẫu.

Ở Lisp, ngay cả trong những ngày đầu, có một thứ gọi là "đối số chức năng" hay FUNARG, không chỉ là một chức năng, mà nó còn chứa một bối cảnh lưu trữ nơi nó có thể nhớ và tương tác với một phần của thế giới bên ngoài.

Nhu cầu tương tự này tồn tại trong các ngôn ngữ OOP, ngoại trừ khi bạn truyền địa chỉ của hàm, bạn cũng phải truyền địa chỉ của đối tượng mà hàm là một phương thức. Đó là hai điều bạn phải vượt qua. Vì vậy, một đại biểu chỉ có vậy, và cho phép mô hình cũ tốt đó vẫn được sử dụng.


3

Dưới đây là một ví dụ đơn giản cho thấy các đại biểu hữu ích có thể tạo mã đơn giản theo nguyên tắc DRY như thế nào. Nó cũng cho phép bạn giữ mã cực kỳ gần với nơi cần thiết.

Action<Button, Action<Button>> prepareButton = 
    (btn, nxt) => { 
        btn.Height = 32;
        btn.Width= 64;
        nxt(btn);
    };

prepareButton(myBtn1, btn => btn.Text = "A");
prepareButton(myBtn2, btn => btn.Text = "B");
prepareButton(myBtn3, btn => btn.Text = "C");

Dưới đây là một ví dụ thực tế về lợi thế mà các đại biểu cung cấp.

protected override void PageInitialize()
{
    const string selectCodeFormat = "javascript:selectCode('{0}', '{1}');";
    const string onClick = "return toggleElement(this);";

    Func<HtmlGenericControl> getElement = null;
    Action<HtmlGenericControl> setElement = null, addChild = null;
    HtmlGenericControl level1Element = null, level2Element = null, level3Element = null, level4Element = null;
    string className = null, code = null, description = null;           

    using (var records = Core.Database.ExecuteRecords("code.SocCodeTree"))
    {
        while (records.Read())
        {
            code = records.GetString("Code");
            description = records.GetString("Description"); 

            if (records.GetString("Level4") != "")
            {
                className = "Level4";
                setElement = e => level4Element = e;
                getElement = () => level4Element;
                addChild = e => level3Element.Controls.Add(e);
            }
            else if (records.GetString("Level3") != "")
            {
                className = "Level3";
                setElement = e => level3Element = e;
                getElement = () => level3Element;
                addChild = e => level2Element.Controls.Add(e);
            }
            else if (records.GetString("Level2") != "")
            {
                className = "Level2";
                setElement = e => level2Element = e;
                getElement = () => level2Element;
                addChild = e => level1Element.Controls.Add(e);
            }
            else
            {
                className = "Level1";
                setElement = e => level1Element = e;
                getElement = () => level1Element;
                addChild = e => Root.Controls.Add(e);
            }

            var child = new HtmlGenericControl("li");
            child.Attributes["class"] = className;
            var span = new HtmlGenericControl("span") { 
                InnerText = code + " - " + description + " - " 
            };
            span.Attributes["onclick"] = onClick;
            child.Controls.Add(span);
            var a = new HtmlAnchor() { 
                InnerText = "Select", 
                HRef = string.Format(selectCodeFormat, code, description) 
            };
            child.Controls.Add(a);
            setElement(new HtmlGenericControl("ul"));
            child.Controls.Add(getElement());
            addChild(child);    
        }
    }
}

2

Cuộc gặp gỡ đầu tiên của tôi với các đại biểu là kiểm tra cập nhật chương trình (cửa sổ mẫu C # 3.5) bằng cách tải xuống tệp từ trang web của tôi, nhưng để tránh kiểm tra cập nhật khóa toàn bộ chương trình, tôi đã sử dụng một đại biểu và một luồng để thực hiện không đồng bộ.


1

Tôi đã thấy các triển khai thú vị của mẫu Chiến lược sử dụng các đại biểu một cách hiệu quả. (tức là chiến lược là một đại biểu)

Cái tôi đang tìm kiếm là tìm đường dẫn trong đó thuật toán tìm đường dẫn là một đại biểu có thể được gán lại trong thời gian chạy để có thể sử dụng các thuật toán khác nhau (BFS vs A *, v.v.)


1

Nhiều mẫu GoF cổ điển có thể được triển khai với các đại biểu: Ví dụ: Mẫu lệnh, Mẫu khách truy cập, Mẫu chiến lược, Mẫu nhà máy và Mẫu quan sát thường có thể được triển khai với một đại biểu đơn giản. Đôi khi, một lớp tốt hơn (ví dụ: khi một lệnh cần một tên hoặc một đối tượng chiến lược cần được tuần tự hóa) nhưng trong hầu hết các trường hợp, sử dụng Action<...>hoặc Func<...>thanh lịch hơn nhiều so với việc tạo giao diện một phương thức chuyên dụng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.