การใช้ตัวแทนการดำเนินการใน C # [ปิด]


132

ฉันทำงานร่วมกับ Action Delegates ใน C # ด้วยความหวังว่าจะได้เรียนรู้เพิ่มเติมเกี่ยวกับพวกเขาและคิดว่าพวกเขาจะมีประโยชน์ในจุดใด

มีใครใช้ Action Delegate หรือไม่และถ้าเป็นเช่นนั้นเพราะเหตุใด หรือคุณช่วยยกตัวอย่างที่อาจเป็นประโยชน์ได้ไหม

คำตอบ:


25

MSDN พูดว่า:

ผู้รับมอบสิทธิ์นี้ใช้โดยเมธอด ArrayForEach และเมธอด ListForEach เพื่อดำเนินการกับแต่ละองค์ประกอบของอาร์เรย์หรือรายการ

ยกเว้นว่าคุณสามารถใช้เป็นตัวแทนทั่วไปที่รับพารามิเตอร์ 1-3 โดยไม่ส่งคืนค่าใด ๆ


ฉันไม่เคยสังเกตเห็น Action เวอร์ชันหลายพารามิเตอร์เหล่านั้น ขอบคุณ.
mackenir

114

นี่คือตัวอย่างเล็ก ๆ ที่แสดงให้เห็นประโยชน์ของ Action delegate

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Action<String> print = new Action<String>(Program.Print);

        List<String> names = new List<String> { "andrew", "nicole" };

        names.ForEach(print);

        Console.Read();
    }

    static void Print(String s)
    {
        Console.WriteLine(s);
    }
}

สังเกตว่าเมธอด foreach จะวนซ้ำการรวบรวมชื่อและเรียกใช้printเมธอดกับสมาชิกแต่ละคนของคอลเล็กชัน นี่เป็นการเปลี่ยนกระบวนทัศน์เล็กน้อยสำหรับพวกเรานักพัฒนา C # เมื่อเราก้าวไปสู่รูปแบบการเขียนโปรแกรมที่มีประโยชน์มากขึ้น (สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิทยาการคอมพิวเตอร์ที่อยู่เบื้องหลังมันอ่าน: http://en.wikipedia.org/wiki/Map_(higher-order_function)

ตอนนี้ถ้าคุณใช้ C # 3 คุณสามารถทำให้มันลื่นขึ้นเล็กน้อยด้วยนิพจน์แลมบ์ดาดังนี้:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<String> names = new List<String> { "andrew", "nicole" };

        names.ForEach(s => Console.WriteLine(s));

        Console.Read();
    }
}

68

สิ่งหนึ่งที่คุณทำได้คือถ้าคุณมีสวิตช์:

switch(SomeEnum)
{
  case SomeEnum.One:
      DoThings(someUser);
      break;
  case SomeEnum.Two:
      DoSomethingElse(someUser);
      break;
}

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

Dictionary<SomeEnum, Action<User>> methodList = 
    new Dictionary<SomeEnum, Action<User>>()

methodList.Add(SomeEnum.One, DoSomething);
methodList.Add(SomeEnum.Two, DoSomethingElse); 

...

methodList[SomeEnum](someUser);

หรือคุณสามารถใช้สิ่งนี้ให้ไกลกว่านี้:

SomeOtherMethod(Action<User> someMethodToUse, User someUser)
{
    someMethodToUse(someUser);
}  

....

var neededMethod = methodList[SomeEnum];
SomeOtherMethod(neededMethod, someUser);

เพียงไม่กี่ตัวอย่าง แน่นอนว่าการใช้งานที่ชัดเจนยิ่งขึ้นคือวิธีการขยาย Linq


เยี่ยมมากฉันคิดว่านี่สามารถใช้เป็นตารางการตัดสินใจได้
Biswanath

3
Nice - นี่คือรูปแบบการปรับโครงสร้างใหม่ "Replace Conditional with Polymorphism" refactoring.com/catalog/replaceConditionalWithPolymorphism.html
David Robbins

16

คุณสามารถใช้การดำเนินการสำหรับตัวจัดการเหตุการณ์แบบสั้น:

btnSubmit.Click += (sender, e) => MessageBox.Show("You clicked save!");

คุณสามารถใช้สำหรับคนยาวได้เช่นกัน btnSubmit.Click + = (ผู้ส่ง, e) => {MessageBox.Show ("คุณคลิกบันทึก!"); MessageBox.Show ("คุณทำได้จริงๆ!"); };
tdgtyugdyugdrugdr

15

ฉันใช้ตัวแทนการดำเนินการเช่นนี้ในโครงการหนึ่งครั้ง:

private static Dictionary<Type, Action<Control>> controldefaults = new Dictionary<Type, Action<Control>>() { 
            {typeof(TextBox), c => ((TextBox)c).Clear()},
            {typeof(CheckBox), c => ((CheckBox)c).Checked = false},
            {typeof(ListBox), c => ((ListBox)c).Items.Clear()},
            {typeof(RadioButton), c => ((RadioButton)c).Checked = false},
            {typeof(GroupBox), c => ((GroupBox)c).Controls.ClearControls()},
            {typeof(Panel), c => ((Panel)c).Controls.ClearControls()}
    };

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


ดีไม่ใช่เรื่องใหญ่ของการเปลี่ยนแปลง แต่มีบางอย่างที่เรียกว่า keyedbyTypeCollection แม้ว่าฉันคิดว่ามันจะล้อมรอบตามคำสั่ง (ประเภทวัตถุ)
Biswanath

13

สำหรับตัวอย่างวิธีใช้ Action <>

Console.WriteLine มีลายเซ็นที่ Action<string>satisifies

    static void Main(string[] args)
    {
        string[] words = "This is as easy as it looks".Split(' ');

        // Passing WriteLine as the action
        Array.ForEach(words, Console.WriteLine);         
    }

หวังว่านี่จะช่วยได้


11

ฉันใช้มันเมื่อฉันจัดการกับการโทรข้ามเธรดที่ผิดกฎหมายตัวอย่างเช่น:

DataRow dr = GetRow();
this.Invoke(new Action(() => {
   txtFname.Text = dr["Fname"].ToString();
   txtLname.Text = dr["Lname"].ToString(); 
   txtMI.Text = dr["MI"].ToString();
   txtSSN.Text = dr["SSN"].ToString();
   txtSSN.ButtonsRight["OpenDialog"].Visible = true;
   txtSSN.ButtonsRight["ListSSN"].Visible = true;
   txtSSN.Focus();
}));

ฉันต้องให้เครดิตกับผู้ใช้ Reed Copsey SO 65358 สำหรับการแก้ปัญหา คำถามเต็มของฉันพร้อมคำตอบคือSO คำถาม 2587930


3

ฉันใช้มันเป็นการโทรกลับในตัวจัดการเหตุการณ์ เมื่อฉันเพิ่มเหตุการณ์ฉันส่งผ่านวิธีการโดยใช้สตริงพารามิเตอร์ นี่คือลักษณะของการเพิ่มขึ้นของเหตุการณ์:

SpecialRequest(this,
    new BalieEventArgs 
    { 
            Message = "A Message", 
            Action = UpdateMethod, 
            Data = someDataObject 
    });

วิธีการ:

   public void UpdateMethod(string SpecialCode){ }

เป็นการประกาศคลาสของเหตุการณ์ Args:

public class MyEventArgs : EventArgs
    {
        public string Message;
        public object Data;
        public Action<String> Action;
    }

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


สวัสดีคุณ Sorskoot ช่วยขยายความได้ว่า UpdateMethod, MyEventArgs และ BalieEventArgs ใหม่เล่นด้วยกันอย่างไร สตริงข้อความถูกส่งไปยัง UpdateMethod: UpdateMethod ("A Message") หรือไม่ วิธีใดใช้วัตถุ "someDataObject" ขอบคุณล่วงหน้า
surfmuggle

2

เราใช้ฟังก์ชัน Action delegate จำนวนมากในการทดสอบ เมื่อเราต้องการสร้างวัตถุเริ่มต้นและต้องแก้ไขในภายหลัง ฉันทำตัวอย่างเล็กน้อย ในการสร้างวัตถุบุคคลเริ่มต้น (John Doe) เราใช้BuildPerson()ฟังก์ชัน ต่อมาเราเพิ่ม Jane Doe เข้าไปด้วย แต่เราแก้ไขวันเกิดชื่อและส่วนสูงของเธอ

public class Program
{
        public static void Main(string[] args)
        {
            var person1 = BuildPerson();

            Console.WriteLine(person1.Firstname);
            Console.WriteLine(person1.Lastname);
            Console.WriteLine(person1.BirthDate);
            Console.WriteLine(person1.Height);

            var person2 = BuildPerson(p =>
            {
                p.Firstname = "Jane";
                p.BirthDate = DateTime.Today;
                p.Height = 1.76;
            });

            Console.WriteLine(person2.Firstname);
            Console.WriteLine(person2.Lastname);
            Console.WriteLine(person2.BirthDate);
            Console.WriteLine(person2.Height);

            Console.Read();
        }

        public static Person BuildPerson(Action<Person> overrideAction = null)
        {
            var person = new Person()
            {
                Firstname = "John",
                Lastname = "Doe",
                BirthDate = new DateTime(2012, 2, 2)
            };

            if (overrideAction != null)
                overrideAction(person);

            return person;
        }
    }

    public class Person
    {
        public string Firstname { get; set; }
        public string Lastname { get; set; }
        public DateTime BirthDate { get; set; }
        public double Height { get; set; }
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.