ฉันทำงานร่วมกับ Action Delegates ใน C # ด้วยความหวังว่าจะได้เรียนรู้เพิ่มเติมเกี่ยวกับพวกเขาและคิดว่าพวกเขาจะมีประโยชน์ในจุดใด
มีใครใช้ Action Delegate หรือไม่และถ้าเป็นเช่นนั้นเพราะเหตุใด หรือคุณช่วยยกตัวอย่างที่อาจเป็นประโยชน์ได้ไหม
ฉันทำงานร่วมกับ Action Delegates ใน C # ด้วยความหวังว่าจะได้เรียนรู้เพิ่มเติมเกี่ยวกับพวกเขาและคิดว่าพวกเขาจะมีประโยชน์ในจุดใด
มีใครใช้ Action Delegate หรือไม่และถ้าเป็นเช่นนั้นเพราะเหตุใด หรือคุณช่วยยกตัวอย่างที่อาจเป็นประโยชน์ได้ไหม
คำตอบ:
MSDN พูดว่า:
ผู้รับมอบสิทธิ์นี้ใช้โดยเมธอด ArrayForEach และเมธอด ListForEach เพื่อดำเนินการกับแต่ละองค์ประกอบของอาร์เรย์หรือรายการ
ยกเว้นว่าคุณสามารถใช้เป็นตัวแทนทั่วไปที่รับพารามิเตอร์ 1-3 โดยไม่ส่งคืนค่าใด ๆ
นี่คือตัวอย่างเล็ก ๆ ที่แสดงให้เห็นประโยชน์ของ 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();
}
}
สิ่งหนึ่งที่คุณทำได้คือถ้าคุณมีสวิตช์:
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
คุณสามารถใช้การดำเนินการสำหรับตัวจัดการเหตุการณ์แบบสั้น:
btnSubmit.Click += (sender, e) => MessageBox.Show("You clicked save!");
ฉันใช้ตัวแทนการดำเนินการเช่นนี้ในโครงการหนึ่งครั้ง:
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()}
};
ซึ่งทั้งหมดนี้จะจัดเก็บการดำเนินการ (การเรียกใช้วิธีการ) กับประเภทของการควบคุมเพื่อให้คุณสามารถล้างการควบคุมทั้งหมดในแบบฟอร์มกลับไปที่ค่าเริ่มต้นได้
สำหรับตัวอย่างวิธีใช้ 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);
}
หวังว่านี่จะช่วยได้
ฉันใช้มันเมื่อฉันจัดการกับการโทรข้ามเธรดที่ผิดกฎหมายตัวอย่างเช่น:
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
ฉันใช้มันเป็นการโทรกลับในตัวจัดการเหตุการณ์ เมื่อฉันเพิ่มเหตุการณ์ฉันส่งผ่านวิธีการโดยใช้สตริงพารามิเตอร์ นี่คือลักษณะของการเพิ่มขึ้นของเหตุการณ์:
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;
}
ด้วยวิธีนี้ฉันสามารถเรียกเมธอดที่ส่งผ่านจากตัวจัดการเหตุการณ์ด้วยพารามิเตอร์บางตัวเพื่ออัปเดตข้อมูล ฉันใช้สิ่งนี้เพื่อขอข้อมูลบางอย่างจากผู้ใช้
เราใช้ฟังก์ชัน 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; }
}