การใช้งาน C # Delegates ในโลกแห่งความเป็นจริง [ปิด]


16

ฉันคิดว่าฉันเข้าใจแนวคิดของผู้ได้รับมอบหมาย C # แต่ฉันพยายามดิ้นรนเพื่อหาตัวอย่างโลกแห่งความจริงที่พวกเขาจะมีประโยชน์ คุณสามารถให้คำตอบโดยละเอียดเกี่ยวกับวิธีการใช้ผู้รับมอบสิทธิ์ C # ในแอปพลิเคชันจริงและปัญหาใดที่พวกเขาทำให้คุณสามารถแก้ไขได้


2
เกือบทุกคลาสเดียวใน. NET Framework จะเปิดเผยชุดของเหตุการณ์บางอย่างดังนั้นคุณจะไป มันเป็นเพียงวิธีการห่อหุ้มหน่วยงานบางส่วน ตัวอย่างเช่นสมมติว่าคุณกำลังนำโครงสร้างไบนารีแบบต้นไม้ทั่วไปใน C. วิธีเดียวที่จะเรียงลำดับทรีของคุณคือการใช้พารามิเตอร์เป็นตัวชี้ฟังก์ชันซึ่งรู้วิธีการเรียงลำดับ
Ed S.

คำตอบ:


16

รหัส GUI ใช้ผู้รับมอบสิทธิ์ในการจัดการเหตุการณ์เช่นการคลิกปุ่มการย้ายหน้าต่าง การใช้ผู้รับมอบสิทธิ์ช่วยให้คุณมีฟังก์ชั่นที่เรียกว่าเมื่อใดก็ตามที่เหตุการณ์เกิดขึ้น ตัวอย่างจะเชื่อมโยงฟังก์ชันที่บันทึกข้อมูลไปยังปุ่ม "บันทึก" บนอินเทอร์เฟซ เมื่อปุ่มถูกคลิกมันจะถูกตั้งค่าให้เรียกใช้งานฟังก์ชั่นที่บันทึกข้อมูล มันมีประโยชน์ในการเขียนโปรแกรม GUI เพราะโปรแกรมทั้งหมดของคุณอาจรอให้ผู้ใช้ทำอะไรและคุณไม่มีทางรู้ว่าพวกเขาจะทำอะไรก่อน การใช้ผู้ร่วมประชุมช่วยให้การทำงานของโปรแกรมของคุณเชื่อมต่อกับ UI ในลักษณะที่ผู้ใช้สามารถทำสิ่งต่าง ๆ ในแบบที่พวกเขาต้องการ


2
++ คุณขวา แต่ฉันยังคงเกลียดมัน :-) ดังนั้นทุกเพศทุกวัยที่ผ่านมาฉันมาด้วยนี้แทน
Mike Dunlavey

12

Linq ใช้Func<T>และAction<T>ตัวแทนทั่วสถานที่เป็นพารามิเตอร์

สิ่งเหล่านี้ช่วยให้คุณใช้การแสดงออกแลมบ์ดาเป็นพารามิเตอร์และกำหนดการกระทำที่จะดำเนินการเป็นส่วนหนึ่งของรายการพารามิเตอร์


12

อะไรก็ตามที่ใช้รูปแบบการสังเกตการณ์น่าจะนำผู้ได้รับมอบหมายไปปฏิบัติ

อ่านคำอธิบายแล้วคุณอาจจินตนาการถึงสถานการณ์ที่คุณจะใช้ การจัดการเหตุการณ์ GUI เป็นตัวอย่างทั่วไป


+1, รูปแบบกลยุทธ์นั้นจริง ๆ ที่ผู้ได้รับมอบหมายส่องแสงนั่นคือคุณมีคลาสที่วิธีการทำบางสิ่งบางอย่าง แต่คุณต้องการให้สิ่งที่จะเปลี่ยนได้และโดยไม่ต้องพึ่งพาโดยตรงตัวแทน Ergo โปรดทราบว่าเหตุการณ์ต่าง ๆ เติมเต็มความต้องการเช่นเดียวกับผู้ได้รับมอบหมายความแตกต่างคือคุณใช้ผู้ได้รับมอบหมายเมื่อคุณต้องการตอบสนองต่อค่าตอบแทนในขณะที่คุณเพิ่งเริ่มต้นเหตุการณ์และสิ่งที่จะเป็น
Homde

9

ผู้รับมอบอำนาจมีประโยชน์ในการเขียนโปรแกรมแบบอะซิงโครนัส

คุณมีคลาสที่ทำข้อมูลแบบอะซิงโครนัสและมีการโทรกลับ คุณสามารถเรียกใช้เมธอดมอบหมายเมื่อเรียกกลับ - และการนำคลาสของคุณไปใช้จะทำตามตรรกะที่อธิบายไว้ในเมธอดของคุณ


9

ผู้ได้รับมอบหมายเป็นประโยชน์อย่างยิ่งสำหรับเป็นวิธีแก้ปัญหาที่หลุมในรูปแบบกลาง โดยพื้นฐานแล้วมีหลายกรณีที่คุณต้องการห่อชุดคำสั่งที่ไม่ซ้ำกันไว้ในชุดคำสั่งทั่วไป มันยากโดยเฉพาะอย่างยิ่งถ้าคำแนะนำก่อนและหลังบิตที่ไม่ซ้ำกันต้องแบ่งปันสถานะ ด้วยผู้รับมอบสิทธิ์คุณสามารถส่งผู้แทนเข้าสู่ฟังก์ชันได้ ฟังก์ชั่นดำเนินการบิตก่อนหน้าดำเนินการมอบหมายแล้วดำเนินการหลังจากบิต


5

ใน "สมัยก่อน" ของภาษาที่ไม่ใช่ OOP เช่น Fortran และ C มันมีประโยชน์อย่างมากที่จะมีรูทีนย่อยได้รับการโต้แย้งซึ่งเป็นตัวชี้ไปยังฟังก์ชั่น ตัวอย่างเช่นqsortฟังก์ชั่นใช้งานได้กับฟังก์ชั่นการเปรียบเทียบที่ผู้ใช้จัดหา มีรูทีนย่อยมากมายสำหรับการแก้สมการเชิงอนุพันธ์สามัญหรือสำหรับการปรับฟังก์ชันให้เหมาะสม

ในระบบหน้าต่างการเรียกกลับทุกชนิดเป็นไปตามรูปแบบเดียวกัน

ใน Lisp แม้ในยุคแรก ๆ มีบางสิ่งที่เรียกว่า "อาร์กิวเมนต์การทำงาน" หรือ FUNARG ซึ่งไม่เพียง แต่เป็นฟังก์ชั่นเท่านั้น แต่ยังมีบริบทการจัดเก็บที่สามารถจดจำและโต้ตอบกับส่วนหนึ่งของโลกภายนอกได้

ความต้องการแบบเดียวกันนี้มีอยู่ในภาษา OOP ยกเว้นเมื่อคุณผ่านที่อยู่ของฟังก์ชั่นคุณต้องผ่านที่อยู่ของวัตถุฟังก์ชั่นเป็นวิธีการ นั่นคือสองสิ่งที่คุณต้องทำ ดังนั้นผู้รับมอบสิทธิ์จึงเป็นเช่นนั้นและอนุญาตให้ยังคงรูปแบบเก่าที่ดีไว้ได้


3

นี่คือตัวอย่างง่ายๆที่แสดงให้เห็นว่าผู้ได้รับมอบหมายที่มีประโยชน์สามารถสร้างรหัสอย่างง่าย ๆ ซึ่งเป็นไปตามหลักการ DRY ได้อย่างไร นอกจากนี้ยังช่วยให้คุณสามารถเก็บรหัสใกล้กับที่จำเป็นมาก

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");

นี่คือตัวอย่างจริงของความได้เปรียบที่ผู้มอบให้

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

การพบกันครั้งแรกของฉันกับผู้เข้าร่วมคือการตรวจสอบการอัปเดตโปรแกรม (windows form C # 3.5) โดยการดาวน์โหลดไฟล์จากเว็บไซต์ของฉัน แต่เพื่อหลีกเลี่ยงการตรวจสอบการอัปเดตการล็อกโปรแกรมทั้งหมดฉันใช้ตัวแทนและเธรด


1

ฉันเห็นการใช้งานที่น่าสนใจของรูปแบบกลยุทธ์ที่ใช้ผู้ได้รับมอบหมายอย่างมีประสิทธิภาพ (เช่นกลยุทธ์เป็นตัวแทน)

สิ่งที่ฉันกำลังมองหาคือการหาเส้นทางโดยที่อัลกอริทึมในการค้นหาเส้นทางเป็นตัวแทนที่สามารถมอบหมาย (อีกครั้ง) ที่รันไทม์เพื่อให้อัลกอริทึมที่แตกต่างสามารถใช้ (BFS กับ A * เป็นต้น)


1

รูปแบบคลาสสิกของ GoF หลายรูปแบบสามารถนำไปใช้กับผู้ได้รับมอบหมายได้ตัวอย่างเช่นรูปแบบคำสั่งรูปแบบผู้เยี่ยมชมรูปแบบกลยุทธ์รูปแบบจากโรงงานและรูปแบบผู้สังเกตการณ์สามารถนำไปใช้กับตัวแทนได้อย่างง่ายดาย บางครั้งคลาสจะดีกว่า (เช่นเมื่อคำสั่งต้องการชื่อหรือวัตถุกลยุทธ์ต้องถูกทำให้เป็นอนุกรม) แต่ในกรณีส่วนใหญ่การใช้Action<...>หรือFunc<...>มีความสง่างามกว่าการสร้างอินเตอร์เฟสแบบวิธีเดียวโดยเฉพาะ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.