คุณใช้ตัวแทนใน C # อะไรบ้าง?
คุณใช้ตัวแทนใน C # อะไรบ้าง?
คำตอบ:
ตอนนี้เรามีนิพจน์แลมบ์ดาและเมธอดที่ไม่ระบุตัวตนใน C # ฉันใช้ผู้รับมอบสิทธิ์มากขึ้น ใน C # 1 ซึ่งคุณมักจะต้องมีวิธีการแยกต่างหากเพื่อใช้ตรรกะการใช้ตัวแทนมักไม่สมเหตุสมผล ทุกวันนี้ฉันใช้ผู้รับมอบสิทธิ์สำหรับ:
ผู้ได้รับมอบหมายมีประโยชน์มากสำหรับวัตถุประสงค์หลายประการ
จุดประสงค์อย่างหนึ่งคือใช้เพื่อกรองลำดับข้อมูล ในกรณีนี้คุณจะใช้เพรดิเคตผู้รับมอบสิทธิ์ซึ่งยอมรับหนึ่งอาร์กิวเมนต์และส่งคืนจริงหรือเท็จขึ้นอยู่กับการใช้งานของผู้รับมอบสิทธิ์เอง
นี่คือตัวอย่างโง่ ๆ - ฉันแน่ใจว่าคุณสามารถคาดเดาสิ่งที่มีประโยชน์มากกว่านี้ได้:
using System;
using System.Linq;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<String> names = new List<String>
{
"Nicole Hare",
"Michael Hare",
"Joe Hare",
"Sammy Hare",
"George Washington",
};
// Here I am passing "inMyFamily" to the "Where" extension method
// on my List<String>. The C# compiler automatically creates
// a delegate instance for me.
IEnumerable<String> myFamily = names.Where(inMyFamily);
foreach (String name in myFamily)
Console.WriteLine(name);
}
static Boolean inMyFamily(String name)
{
return name.EndsWith("Hare");
}
}
static Boolean inMyFamily(String name)
วิธีการเป็นตัวแทน ที่ไหนรับผู้รับมอบสิทธิ์เป็นพารามิเตอร์ เนื่องจากผู้รับมอบสิทธิ์เป็นเพียงตัวชี้ฟังก์ชันเมื่อคุณส่งชื่อเมธอดเข้าไปในชื่อ.Where(delegate)
ที่จะกลายเป็นผู้รับมอบสิทธิ์ เนื่องจาก inMyFamily ส่งคืนประเภทบูลีนจึงถือว่าเป็นเพรดิเคต เพรดิเคตเป็นเพียงผู้รับมอบสิทธิ์ที่ส่งคืนบูลีน
พบอีกคำตอบที่น่าสนใจ:
เพื่อนร่วมงานเพิ่งถามฉันคำถามนี้ - อะไรคือจุดที่ผู้ได้รับมอบหมายใน. NET? คำตอบของฉันสั้นมากและเป็นคำตอบที่เขาไม่พบทางออนไลน์: เพื่อชะลอการดำเนินการของวิธีการ
ที่มา: LosTechies
เช่นเดียวกับที่ LINQ กำลังทำอยู่
คุณสามารถใช้ผู้รับมอบสิทธิ์เพื่อประกาศตัวแปรและพารามิเตอร์ประเภทฟังก์ชัน
ตัวอย่าง
พิจารณารูปแบบ "การยืมทรัพยากร" คุณต้องการควบคุมการสร้างและล้างทรัพยากรในขณะที่อนุญาตให้รหัสไคลเอ็นต์ "ยืม" ทรัพยากรระหว่างกัน
นี่เป็นการประกาศประเภทผู้รับมอบสิทธิ์
public delegate void DataReaderUser( System.Data.IDataReader dataReader );
วิธีการใด ๆ ที่ตรงกับลายเซ็นนี้สามารถใช้เพื่อสร้างอินสแตนซ์ผู้แทนประเภทนี้ได้ ใน C # 2.0 สามารถทำได้โดยปริยายเพียงแค่ใช้ชื่อเมธอดและใช้เมธอดที่ไม่ระบุตัวตน
วิธีนี้ใช้ประเภทเป็นพารามิเตอร์ สังเกตการร้องขอของผู้รับมอบสิทธิ์
public class DataProvider
{
protected string _connectionString;
public DataProvider( string psConnectionString )
{
_connectionString = psConnectionString;
}
public void UseReader( string psSELECT, DataReaderUser readerUser )
{
using ( SqlConnection connection = new SqlConnection( _connectionString ) )
try
{
SqlCommand command = new SqlCommand( psSELECT, connection );
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while ( reader.Read() )
readerUser( reader ); // the delegate is invoked
}
catch ( System.Exception ex )
{
// handle exception
throw ex;
}
}
}
สามารถเรียกใช้ฟังก์ชันด้วยวิธีการไม่ระบุชื่อได้ดังนี้ โปรดทราบว่าวิธีการไม่ระบุชื่อสามารถใช้ตัวแปรที่ประกาศภายนอกตัวมันเอง สิ่งนี้มีประโยชน์มาก (แม้ว่าตัวอย่างจะมีการจัดทำขึ้นเล็กน้อย)
string sTableName = "test";
string sQuery = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='" + sTableName + "'";
DataProvider.UseReader( sQuery,
delegate( System.Data.IDataReader reader )
{
Console.WriteLine( sTableName + "." + reader[0] );
} );
ผู้ร่วมประชุมมักจะใช้แทนอินเทอร์เฟซด้วยวิธีการเดียวตัวอย่างทั่วไปของสิ่งนี้คือรูปแบบผู้สังเกตการณ์ ในภาษาอื่น ๆ หากคุณต้องการรับการแจ้งเตือนว่ามีบางอย่างเกิดขึ้นคุณอาจกำหนดสิ่งต่างๆเช่น:
class IObserver{ void Notify(...); }
ใน C # มักจะแสดงออกโดยใช้เหตุการณ์โดยที่ตัวจัดการคือผู้รับมอบสิทธิ์ตัวอย่างเช่น:
myObject.SomeEvent += delegate{ Console.WriteLine("..."); };
อีกหนึ่งสถานที่ที่ดีในการใช้ผู้รับมอบสิทธิ์หากคุณต้องส่งเพรดิเคตลงในฟังก์ชันตัวอย่างเช่นเมื่อเลือกชุดของรายการจากรายการ:
myList.Where(i => i > 10);
ข้างต้นเป็นตัวอย่างของไวยากรณ์แลมบ์ดาซึ่งสามารถเขียนได้ดังนี้:
myList.Where(delegate(int i){ return i > 10; });
สถานที่อื่นที่สามารถใช้ตัวแทนได้อย่างมีประโยชน์คือการลงทะเบียนฟังก์ชั่นของโรงงานเช่น:
myFactory.RegisterFactory(Widgets.Foo, () => new FooWidget());
var widget = myFactory.BuildWidget(Widgets.Foo);
ฉันหวังว่านี่จะช่วยได้!
ฉันมาช้าจริงๆ แต่ฉันมีปัญหาในการหาจุดประสงค์ของผู้ได้รับมอบหมายในวันนี้และเขียนโปรแกรมง่ายๆสองโปรแกรมที่ให้ผลลัพธ์เดียวกันกับที่ฉันคิดว่าอธิบายจุดประสงค์ของพวกเขาได้ดี
NoDelegates.cs
using System;
public class Test {
public const int MAX_VALUE = 255;
public const int MIN_VALUE = 10;
public static void checkInt(int a) {
Console.Write("checkInt result of {0}: ", a);
if (a < MAX_VALUE && a > MIN_VALUE)
Console.WriteLine("max and min value is valid");
else
Console.WriteLine("max and min value is not valid");
}
public static void checkMax(int a) {
Console.Write("checkMax result of {0}: ", a);
if (a < MAX_VALUE)
Console.WriteLine("max value is valid");
else
Console.WriteLine("max value is not valid");
}
public static void checkMin(int a) {
Console.Write("checkMin result of {0}: ", a);
if (a > MIN_VALUE)
Console.WriteLine("min value is valid");
else
Console.WriteLine("min value is not valid");
Console.WriteLine("");
}
}
public class Driver {
public static void Main(string [] args) {
Test.checkInt(1);
Test.checkMax(1);
Test.checkMin(1);
Test.checkInt(10);
Test.checkMax(10);
Test.checkMin(10);
Test.checkInt(20);
Test.checkMax(20);
Test.checkMin(20);
Test.checkInt(30);
Test.checkMax(30);
Test.checkMin(30);
Test.checkInt(254);
Test.checkMax(254);
Test.checkMin(254);
Test.checkInt(255);
Test.checkMax(255);
Test.checkMin(255);
Test.checkInt(256);
Test.checkMax(256);
Test.checkMin(256);
}
}
Delegates.cs
using System;
public delegate void Valid(int a);
public class Test {
public const int MAX_VALUE = 255;
public const int MIN_VALUE = 10;
public static void checkInt(int a) {
Console.Write("checkInt result of {0}: ", a);
if (a < MAX_VALUE && a > MIN_VALUE)
Console.WriteLine("max and min value is valid");
else
Console.WriteLine("max and min value is not valid");
}
public static void checkMax(int a) {
Console.Write("checkMax result of {0}: ", a);
if (a < MAX_VALUE)
Console.WriteLine("max value is valid");
else
Console.WriteLine("max value is not valid");
}
public static void checkMin(int a) {
Console.Write("checkMin result of {0}: ", a);
if (a > MIN_VALUE)
Console.WriteLine("min value is valid");
else
Console.WriteLine("min value is not valid");
Console.WriteLine("");
}
}
public class Driver {
public static void Main(string [] args) {
Valid v1 = new Valid(Test.checkInt);
v1 += new Valid(Test.checkMax);
v1 += new Valid(Test.checkMin);
v1(1);
v1(10);
v1(20);
v1(30);
v1(254);
v1(255);
v1(256);
}
}
การใช้งานที่แตกต่างกันเล็กน้อยคือการเพิ่มความเร็วในการสะท้อน กล่าวคือแทนที่จะใช้การสะท้อนในแต่ละครั้งคุณสามารถใช้Delegate.CreateDelegate
เพื่อสร้าง (พิมพ์) มอบหมายให้กับวิธีการ (a MethodInfo
) และเรียกผู้รับมอบสิทธิ์นั้นแทน จากนั้นจะเร็วกว่ามากต่อการโทรเนื่องจากการตรวจสอบได้ดำเนินการไปแล้ว
ด้วยExpression
คุณยังสามารถทำเช่นเดียวกันในการสร้างรหัสในการบิน - ตัวอย่างเช่นคุณสามารถสร้างExpression
ที่แสดงถึงผู้ประกอบการ + สำหรับประเภทได้รับการแต่งตั้งที่รันไทม์ (เพื่อให้การสนับสนุนผู้ประกอบการสำหรับ generics, ซึ่งเป็นภาษาที่ไม่ได้ให้) ; และคุณสามารถรวบรวมExpression
ไปยังผู้รับมอบสิทธิ์ที่พิมพ์ - งานเสร็จแล้ว
ผู้ร่วมประชุมจะถูกใช้ทุกครั้งที่คุณใช้กิจกรรมนั่นคือกลไกที่พวกเขาทำงาน
นอกจากนี้ผู้รับมอบสิทธิ์ยังมีประโยชน์อย่างมากสำหรับสิ่งต่างๆเช่นการใช้คำค้นหา LINQ ตัวอย่างเช่นการสืบค้น LINQ จำนวนมากใช้ตัวแทน (บ่อยครั้งFunc<T,TResult>
) ซึ่งสามารถใช้สำหรับการกรอง
สมัครสมาชิก eventhandlers เหตุการณ์
ตัวอย่างเช่นอาจจะเห็นเป็นที่นี่ คุณมีวิธีการประมวลผลวัตถุที่ตรงตามข้อกำหนดบางประการ อย่างไรก็ตามคุณต้องการให้สามารถประมวลผลวัตถุได้หลายวิธี แทนที่จะต้องสร้างวิธีการแยกต่างหากคุณสามารถกำหนดวิธีการจับคู่ที่ประมวลผลวัตถุให้กับผู้รับมอบสิทธิ์และส่งผู้รับมอบสิทธิ์ไปยังวิธีการที่เลือกวัตถุ ด้วยวิธีนี้คุณสามารถกำหนดวิธีการต่างๆให้กับวิธีการเลือกวิธีเดียว ฉันพยายามทำให้เรื่องนี้เข้าใจได้ง่าย
ฉันใช้ผู้รับมอบสิทธิ์เพื่อสื่อสารกับเธรด
ตัวอย่างเช่นฉันอาจมีแอป win form ที่ดาวน์โหลดไฟล์ แอปจะเริ่มเธรดผู้ปฏิบัติงานเพื่อทำการดาวน์โหลด (ซึ่งป้องกันไม่ให้ GUI ล็อก) เธรดผู้ปฏิบัติงานใช้ผู้รับมอบสิทธิ์ในการส่งข้อความสถานะ (เช่นความคืบหน้าในการดาวน์โหลด) กลับไปที่โปรแกรมหลักเพื่อให้ GUI สามารถอัปเดตแถบสถานะได้
สำหรับตัวจัดการเหตุการณ์
เพื่อส่งผ่านเมธอดในพารามิเตอร์วิธีการ
บรรทัดแรกของการใช้งานคือการแทนที่รูปแบบ Observer / Observable (เหตุการณ์) ประการที่สองรูปแบบกลยุทธ์ที่สวยงามสวยงาม สามารถรวบรวมประเพณีอื่น ๆ ได้มากมายแม้ว่าจะลึกลับกว่าสองข้อแรกที่ฉันคิด
เหตุการณ์การดำเนินการอื่น ๆ
เมื่อใดก็ตามที่คุณต้องการสรุปพฤติกรรม แต่เรียกใช้ในลักษณะเดียวกัน เหตุการณ์ Handlers ฟังก์ชั่นโทรกลับ ฯลฯ คุณสามารถบรรลุสิ่งที่คล้ายกันโดยใช้การเชื่อมต่อและปลดเปลื้อง แต่บางครั้งพฤติกรรมไม่จำเป็นต้องผูกติดอยู่กับประเภทหรือวัตถุ บางครั้งคุณก็มีพฤติกรรมที่ต้องการห่อหุ้ม
การเริ่มต้นพารามิเตอร์ขี้เกียจ! นอกเหนือจากคำตอบก่อนหน้านี้ทั้งหมด (รูปแบบกลยุทธ์รูปแบบผู้สังเกตการณ์ ฯลฯ ) ผู้รับมอบสิทธิ์ยังช่วยให้คุณจัดการกับการเริ่มต้นพารามิเตอร์ได้ ตัวอย่างเช่นสมมติว่าคุณมีฟังก์ชัน Download () ซึ่งใช้เวลาค่อนข้างมากและส่งคืน DownloadedObject บางรายการ วัตถุนี้ถูกใช้โดยที่เก็บข้อมูลขึ้นอยู่กับเงื่อนไขบางประการ โดยทั่วไปคุณจะ:
storage.Store(conditions, Download(item))
อย่างไรก็ตามด้วยผู้รับมอบสิทธิ์ (lambdas ที่แม่นยำยิ่งขึ้น) คุณสามารถทำสิ่งต่อไปนี้ได้โดยเปลี่ยนลายเซ็นของร้านค้าเพื่อให้ได้รับเงื่อนไขและ Func <Item, DownloadedObject> และใช้ในลักษณะนี้:
storage.Store(conditions, (item) => Download(item))
ดังนั้นพื้นที่เก็บข้อมูลจะประเมินผู้รับมอบสิทธิ์ในกรณีที่จำเป็นเท่านั้นการดำเนินการดาวน์โหลดขึ้นอยู่กับเงื่อนไข
การใช้ผู้รับมอบสิทธิ์
พารามิเตอร์เปรียบเทียบในอาร์เรย์ In Array.Sort (T [], การเปรียบเทียบการเปรียบเทียบ), List.Sort (การเปรียบเทียบการเปรียบเทียบ) ฯลฯ
เท่าที่ฉันทราบผู้ร่วมประชุมสามารถแปลงเป็นตัวชี้ฟังก์ชันได้ สิ่งนี้ทำให้ชีวิตง่ายขึ้นมากเมื่อทำงานร่วมกับโค้ดเนทีฟที่ใช้พอยน์เตอร์ของฟังก์ชันเนื่องจากสามารถใช้งานเชิงวัตถุได้อย่างมีประสิทธิภาพแม้ว่าโปรแกรมเมอร์ดั้งเดิมจะไม่ได้จัดเตรียมไว้ให้สิ่งนั้นเกิดขึ้นก็ตาม
Delegate ใช้เพื่อเรียกวิธีการโดยอ้างอิง ตัวอย่างเช่น:
delegate void del_(int no1,int no2);
class Math
{
public static void add(int x,int y)
{
Console.WriteLine(x+y);
}
public static void sub(int x,int y)
{
Console.WriteLine(x-y);
}
}
class Program
{
static void Main(string[] args)
{
del_ d1 = new del_(Math.add);
d1(10, 20);
del_ d2 = new del_(Math.sub);
d2(20, 10);
Console.ReadKey();
}
}