อะไรคือความแตกต่างระหว่างผู้ได้รับมอบหมายและเหตุการณ์? ทั้งคู่ไม่เก็บการอ้างอิงถึงฟังก์ชันที่สามารถเรียกใช้งานได้หรือ
อะไรคือความแตกต่างระหว่างผู้ได้รับมอบหมายและเหตุการณ์? ทั้งคู่ไม่เก็บการอ้างอิงถึงฟังก์ชันที่สามารถเรียกใช้งานได้หรือ
คำตอบ:
การประกาศเหตุการณ์จะเพิ่มเลเยอร์ของนามธรรมและการป้องกันในอินสแตนซ์ของผู้รับมอบสิทธิ์ การป้องกันนี้จะป้องกันไม่ให้ไคลเอนต์ของผู้รับมอบสิทธิ์ตั้งค่าผู้รับมอบสิทธิ์และรายการการเรียกใช้และอนุญาตให้เพิ่มหรือลบเป้าหมายออกจากรายการการเรียกใช้
เพื่อทำความเข้าใจความแตกต่างคุณสามารถดูตัวอย่าง 2 นี้
ตัวอย่างกับผู้ได้รับมอบหมาย (ในกรณีนี้คือการกระทำ - นั่นคือประเภทของตัวแทนที่ไม่ส่งคืนค่า)
public class Animal
{
public Action Run {get; set;}
public void RaiseEvent()
{
if (Run != null)
{
Run();
}
}
}
หากต้องการใช้ผู้รับมอบสิทธิ์คุณควรทำสิ่งนี้:
Animal animal= new Animal();
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running") ;
animal.RaiseEvent();
รหัสนี้ทำงานได้ดี แต่คุณอาจมีจุดอ่อน
ตัวอย่างเช่นถ้าฉันเขียนสิ่งนี้:
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running");
animal.Run = () => Console.WriteLine("I'm sleeping") ;
ด้วยรหัสบรรทัดสุดท้ายฉันได้แทนที่พฤติกรรมก่อนหน้านี้เพียงแค่ขาดหายไปหนึ่งรายการ+
(ฉันใช้=
แทน+=
)
อีกจุดที่อ่อนแอคือว่าชั้นซึ่งใช้ของคุณทุกAnimal
ระดับสามารถเพิ่มเพียงแค่เรียกมันว่าRaiseEvent
animal.RaiseEvent()
เพื่อหลีกเลี่ยงจุดอ่อนเหล่านี้คุณสามารถใช้events
ใน c #
คลาสสัตว์ของคุณจะเปลี่ยนแปลงด้วยวิธีนี้:
public class ArgsSpecial : EventArgs
{
public ArgsSpecial (string val)
{
Operation=val;
}
public string Operation {get; set;}
}
public class Animal
{
// Empty delegate. In this way you are sure that value is always != null
// because no one outside of the class can change it.
public event EventHandler<ArgsSpecial> Run = delegate{}
public void RaiseEvent()
{
Run(this, new ArgsSpecial("Run faster"));
}
}
เพื่อโทรเหตุการณ์
Animal animal= new Animal();
animal.Run += (sender, e) => Console.WriteLine("I'm running. My value is {0}", e.Operation);
animal.RaiseEvent();
แตกต่าง:
หมายเหตุ:
EventHandler ได้รับการประกาศให้เป็นตัวแทนต่อไปนี้:
public delegate void EventHandler (object sender, EventArgs e)
มันต้องใช้ผู้ส่ง (ของประเภทวัตถุ) และข้อโต้แย้งเหตุการณ์ ผู้ส่งเป็นโมฆะหากมาจากวิธีการคงที่
ตัวอย่างนี้ซึ่งใช้EventHandler<ArgsSpecial>
สามารถเขียนได้โดยใช้EventHandler
แทน
อ้างอิงที่นี่สำหรับเอกสารเกี่ยวกับ EventHandler
RaiseEvent
ตราบใดที่วิธีการโทรมีการเข้าถึงอินสแตนซ์ของanimal
ในรหัสที่ใช้เหตุการณ์หรือไม่
animal.Run(this, new ArgsSpecial("Run faster");
?
นอกจากคุณสมบัติทางด้านวากยสัมพันธ์และการปฏิบัติการแล้วยังมีความแตกต่างทางอรรถศาสตร์
เทมเพลตของฟังก์ชันผู้ได้รับมอบหมาย นั่นคือพวกเขาแสดงสัญญาฟังก์ชั่นจะต้องปฏิบัติตามเพื่อให้ได้รับการพิจารณา "ประเภท" ของผู้ได้รับมอบหมาย
เหตุการณ์เป็นตัวแทน ... ดีกิจกรรม พวกเขาตั้งใจที่จะเตือนผู้อื่นเมื่อมีอะไรเกิดขึ้นและใช่พวกเขาปฏิบัติตามคำจำกัดความของผู้ร่วมประชุม แต่พวกเขาไม่เหมือนกัน
แม้ว่าพวกเขาจะเป็นสิ่งเดียวกัน (syntactically และในรหัส IL) จะยังคงมีความแตกต่างทางความหมาย โดยทั่วไปฉันต้องการชื่อที่แตกต่างกันสองชื่อสำหรับแนวคิดที่แตกต่างกันสองรายการแม้ว่าจะมีการใช้งานในลักษณะเดียวกัน (ซึ่งไม่ได้หมายความว่าฉันต้องการมีรหัสเดียวกันสองครั้ง)
นี่เป็นอีกลิงค์ที่ดีในการอ้างอิง http://csharpindepth.com/Articles/Chapter2/Events.aspx
สั้น ๆ นำออกไปจากบทความ - เหตุการณ์คือการห่อหุ้มของผู้ได้รับมอบหมาย
อ้างอิงจากบทความ:
สมมติว่าเหตุการณ์ไม่มีอยู่ในแนวคิดใน C # /. NET ชั้นเรียนอื่นจะสมัครเข้าร่วมกิจกรรมได้อย่างไร สามตัวเลือก:
ตัวแปรผู้แทนสาธารณะ
ตัวแปรผู้แทนได้รับการสนับสนุนโดยพร็อพเพอร์ตี้
ตัวแปรผู้รับมอบสิทธิ์ด้วยวิธี AddXXXHandler และ RemoveXXXHandler
ตัวเลือกที่ 1 น่ากลัวอย่างเห็นได้ชัดด้วยเหตุผลปกติทั้งหมดที่เราเกลียดตัวแปรสาธารณะ
ตัวเลือกที่ 2 นั้นดีกว่าเล็กน้อย แต่ช่วยให้สมาชิกสามารถแทนที่ซึ่งกันและกันได้อย่างมีประสิทธิภาพ - มันจะง่ายเกินไปที่จะเขียน someInstance.MyEvent = eventHandler; ซึ่งจะแทนที่ตัวจัดการเหตุการณ์ที่มีอยู่แทนที่จะเพิ่มตัวจัดการเหตุการณ์ใหม่ นอกจากนี้คุณยังต้องเขียนคุณสมบัติ
ตัวเลือกที่ 3 นั้นเป็นสิ่งที่เหตุการณ์ให้คุณ แต่มีการรับประกันแบบแผน (สร้างโดยคอมไพเลอร์และสำรองโดยการตั้งค่าสถานะพิเศษใน IL) และการใช้งาน "ฟรี" ถ้าคุณพอใจกับความหมายที่เหตุการณ์คล้ายสนามให้คุณ การสมัครและยกเลิกการสมัครจากเหตุการณ์ถูกห่อหุ้มโดยไม่อนุญาตให้เข้าถึงรายการตัวจัดการเหตุการณ์โดยไม่ตั้งใจและภาษาสามารถทำให้สิ่งต่าง ๆ ง่ายขึ้นโดยจัดเตรียมไวยากรณ์สำหรับทั้งการประกาศและการสมัครสมาชิก
public Delegate
ตัวแปรจะถูกเปิดเผย "ข้อมูล" แต่ที่ดีที่สุดของ OOP ความรู้ของฉันไม่เคยกล่าวถึงแนวความคิดใด ๆ ค่อนข้างเหมือน Delegate
(มันไม่เป็น "วัตถุ" หรือเป็น "ข้อความ") และ. NET จะปฏิบัติต่อผู้ได้รับมอบหมายเช่นเดียวกับข้อมูลจริงๆ
AddXXXHandler
วิธีการของคุณเองด้วยprivate Delegate
ตัวแปรอาจเป็นตัวเลือกที่ดี ในกรณีนี้คุณสามารถตรวจสอบเพื่อดูว่ามีการตั้งค่าตัวจัดการแล้วและตอบสนองอย่างเหมาะสม นี่อาจเป็นการตั้งค่าที่ดีหากคุณต้องการให้วัตถุที่ถืออยู่Delegate
นั้นสามารถลบตัวจัดการทั้งหมดได้ ( event
ไม่ได้ให้วิธีการใด ๆ กับคุณ)
หมายเหตุ: หากคุณเข้าถึงC # 5.0 Unleashedให้อ่าน "ข้อ จำกัด ในการใช้งานของผู้ได้รับมอบหมาย" ในบทที่ 18 เรื่อง "กิจกรรม" เพื่อทำความเข้าใจความแตกต่างระหว่างทั้งสองให้ดีขึ้น
มันช่วยให้ฉันมีตัวอย่างที่เป็นรูปธรรมและเรียบง่ายอยู่เสมอ ดังนั้นนี่คือหนึ่งในชุมชน ก่อนอื่นฉันจะแสดงวิธีที่คุณสามารถใช้ผู้ได้รับมอบหมายเพียงอย่างเดียวเพื่อทำสิ่งที่กิจกรรมทำเพื่อเรา EventHandler
แล้วฉันจะแสดงให้เห็นว่าการแก้ปัญหาเดียวกันจะทำงานร่วมกับอินสแตนซ์ของ จากนั้นฉันอธิบายว่าทำไมเราไม่ต้องการทำสิ่งที่ฉันอธิบายในตัวอย่างแรก โพสต์นี้ได้แรงบันดาลใจจากบทความโดย John Skeet
ตัวอย่างที่ 1: การใช้ตัวแทนสาธารณะ
สมมติว่าฉันมีแอพ WinForms พร้อมกล่องแบบเลื่อนลงกล่องเดียว List<Person>
หล่นลงถูกผูกไว้กับผู้ โดยที่ Person มีคุณสมบัติของ Id, ชื่อ, ชื่อเล่น, HairColor ในรูปแบบหลักคือการควบคุมผู้ใช้ที่กำหนดเองที่แสดงคุณสมบัติของบุคคลนั้น เมื่อมีคนเลือกบุคคลในรายการแบบหล่นลงป้ายกำกับในการปรับปรุงการควบคุมผู้ใช้เพื่อแสดงคุณสมบัติของบุคคลที่เลือก
นี่คือวิธีการทำงาน เรามีสามไฟล์ที่ช่วยให้เรารวบรวมสิ่งนี้เข้าด้วยกัน:
นี่คือรหัสที่เกี่ยวข้องสำหรับแต่ละคลาส:
class Mediator
{
public delegate void PersonChangedDelegate(Person p); //delegate type definition
public static PersonChangedDelegate PersonChangedDel; //delegate instance. Detail view will "subscribe" to this.
public static void OnPersonChanged(Person p) //Form1 will call this when the drop-down changes.
{
if (PersonChangedDel != null)
{
PersonChangedDel(p);
}
}
}
นี่คือการควบคุมผู้ใช้ของเรา:
public partial class DetailView : UserControl
{
public DetailView()
{
InitializeComponent();
Mediator.PersonChangedDel += DetailView_PersonChanged;
}
void DetailView_PersonChanged(Person p)
{
BindData(p);
}
public void BindData(Person p)
{
lblPersonHairColor.Text = p.HairColor;
lblPersonId.Text = p.IdPerson.ToString();
lblPersonName.Text = p.Name;
lblPersonNickName.Text = p.NickName;
}
}
ในที่สุดเราก็มีรหัสต่อไปนี้ใน Form1.cs ของเรา ที่นี่เรากำลังโทรหา OnPersonChanged ซึ่งจะเรียกรหัสใด ๆ ที่สมัครเป็นผู้รับมอบสิทธิ์
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
Mediator.OnPersonChanged((Person)comboBox1.SelectedItem); //Call the mediator's OnPersonChanged method. This will in turn call all the methods assigned (i.e. subscribed to) to the delegate -- in this case `DetailView_PersonChanged`.
}
ตกลง. ดังนั้นที่ว่าคุณจะได้รับนี้ทำงานโดยไม่ต้องใช้เหตุการณ์ที่เกิดขึ้นและเพียงแค่ใช้ที่ได้รับมอบหมาย เราแค่ใส่ตัวแทนสาธารณะเข้าชั้นเรียน - คุณสามารถทำให้มันคงที่หรือเดี่ยวหรืออะไรก็ได้ ยิ่งใหญ่
แต่ฉันไม่ต้องการทำสิ่งที่ฉันอธิบายไว้ข้างต้น เนื่องจากเขตข้อมูลสาธารณะไม่ดีด้วยเหตุผลหลายประการ ตัวเลือกของเราคืออะไร? ตามที่ John Skeet อธิบายนี่คือตัวเลือกของเรา:
PersonChangedDel = null
. เช็ดออกทั้งหมดของการสมัครสมาชิกอื่น ๆ ปัญหาอื่น ๆ ที่ยังคงอยู่ที่นี่คือเนื่องจากผู้ใช้สามารถเข้าถึงผู้รับมอบสิทธิ์พวกเขาสามารถเรียกใช้เป้าหมายในรายการการเรียกร้อง - เราไม่ต้องการให้ผู้ใช้ภายนอกสามารถเข้าถึงเมื่อจะเพิ่มกิจกรรมของเราตัวเลือกที่สามนี้เป็นสิ่งสำคัญที่เหตุการณ์ให้เรา เมื่อเราประกาศ EventHandler มันทำให้เราสามารถเข้าถึงผู้ได้รับมอบหมาย - ไม่ใช่สาธารณะไม่ใช่ทรัพย์สิน แต่เป็นสิ่งนี้เราเรียกเหตุการณ์ที่เพิ่งเพิ่ม / ลบ accessors
มาดูกันว่าโปรแกรมนี้หน้าตาเป็นอย่างไร แต่ตอนนี้ใช้กิจกรรมแทนผู้แทนสาธารณะ (ฉันเปลี่ยน Mediator ของเราเป็นซิงเกิลตัน):
ตัวอย่างที่ 2: ด้วย EventHandler แทนที่จะเป็นตัวแทนสาธารณะ
คนกลาง:
class Mediator
{
private static readonly Mediator _Instance = new Mediator();
private Mediator() { }
public static Mediator GetInstance()
{
return _Instance;
}
public event EventHandler<PersonChangedEventArgs> PersonChanged; //this is just a property we expose to add items to the delegate.
public void OnPersonChanged(object sender, Person p)
{
var personChangedDelegate = PersonChanged as EventHandler<PersonChangedEventArgs>;
if (personChangedDelegate != null)
{
personChangedDelegate(sender, new PersonChangedEventArgs() { Person = p });
}
}
}
โปรดสังเกตว่าถ้าคุณ F12 บน EventHandler มันจะแสดงให้คุณเห็นว่าคำจำกัดความเป็นเพียงตัวแทนทั่วไปที่ได้รับการกล่าวขวัญพร้อมกับวัตถุ "ผู้ส่ง" เพิ่มเติม:
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
การควบคุมผู้ใช้:
public partial class DetailView : UserControl
{
public DetailView()
{
InitializeComponent();
Mediator.GetInstance().PersonChanged += DetailView_PersonChanged;
}
void DetailView_PersonChanged(object sender, PersonChangedEventArgs e)
{
BindData(e.Person);
}
public void BindData(Person p)
{
lblPersonHairColor.Text = p.HairColor;
lblPersonId.Text = p.IdPerson.ToString();
lblPersonName.Text = p.Name;
lblPersonNickName.Text = p.NickName;
}
}
สุดท้ายนี่คือรหัส Form1.cs:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
Mediator.GetInstance().OnPersonChanged(this, (Person)comboBox1.SelectedItem);
}
เนื่องจาก EventHandler ต้องการและ EventArgs เป็นพารามิเตอร์ฉันสร้างคลาสนี้มีเพียงคุณสมบัติเดียวในนั้น:
class PersonChangedEventArgs
{
public Person Person { get; set; }
}
หวังว่าจะแสดงให้คุณเห็นเล็กน้อยเกี่ยวกับสาเหตุที่เรามีเหตุการณ์และความแตกต่าง - แต่ใช้งานได้เหมือนกัน - ในฐานะผู้ได้รับมอบหมาย
The other problem that remains here is that since the users have access to the delegate, they can invoke the targets in the invocation list -- we don't want external users having access to when to raise our events
- ในเวอร์ชันล่าสุดของMediator
คุณยังสามารถโทรหาOnPersonChange
เมื่อใดก็ตามที่คุณมีการอ้างอิงถึงซิงเกิล บางทีคุณควรพูดถึงว่าMediator
วิธีการนี้ไม่ได้ป้องกันพฤติกรรมเฉพาะนั้นและอยู่ใกล้กับบัสเหตุการณ์
คุณยังสามารถใช้เหตุการณ์ในการประกาศอินเทอร์เฟซไม่ใช่สำหรับผู้รับมอบสิทธิ์
Action a { get; set; }
นิยามภายในอินเตอร์เฟส
ช่างเป็นความเข้าใจผิดที่ยอดเยี่ยมระหว่างเหตุการณ์และตัวแทน !!! ผู้รับมอบสิทธิ์จะระบุ TYPE (เช่น a class
หรือ a interface
do) ในขณะที่เหตุการณ์เป็นเพียงประเภทของสมาชิก (เช่นเขตข้อมูลคุณสมบัติ ฯลฯ ) และเช่นเดียวกับสมาชิกประเภทอื่น ๆ กิจกรรมก็มีประเภทเช่นกัน แต่ในกรณีของเหตุการณ์ประเภทของเหตุการณ์จะต้องระบุโดยผู้รับมอบสิทธิ์ ตัวอย่างเช่นคุณไม่สามารถประกาศเหตุการณ์ประเภทที่กำหนดโดยอินเทอร์เฟซ
สรุปเราสามารถทำให้ต่อไปนี้สังเกต: ชนิดของเหตุการณ์ที่จะต้องกำหนดโดยผู้แทน นี่คือความสัมพันธ์หลักระหว่างเหตุการณ์และผู้รับมอบสิทธิ์และมีการอธิบายไว้ในส่วนII.18 การกำหนดเหตุการณ์ของพาร์ติชัน ECMA-335 (CLI) I ถึง VI :
ในการใช้งานทั่วไป TypeSpec (ถ้ามี) ระบุตัวแทนที่มีลายเซ็นตรงกับข้อโต้แย้งที่ส่งผ่านไปยังวิธีการดับเพลิงของเหตุการณ์
แต่ความเป็นจริงนี้ไม่ได้หมายความว่าเหตุการณ์จะใช้ข้อมูลการสนับสนุนของผู้ร่วมประชุม ในความเป็นจริงเหตุการณ์อาจใช้เขตข้อมูลสำรองของประเภทโครงสร้างข้อมูลที่แตกต่างกันที่คุณเลือก หากคุณใช้เหตุการณ์อย่างชัดเจนใน C # คุณมีอิสระที่จะเลือกวิธีที่คุณจัดเก็บจัดการเหตุการณ์ (ทราบว่าตัวจัดการเหตุการณ์กรณีของประเภทของเหตุการณ์ที่เกิดขึ้นซึ่งจะเป็น mandatorily ประเภทผู้รับมอบสิทธิ์ --- จากก่อนหน้านี้การสังเกต ) แต่คุณสามารถจัดเก็บตัวจัดการเหตุการณ์เหล่านั้น (ซึ่งเป็นอินสแตนซ์ของผู้รับมอบสิทธิ์) ในโครงสร้างข้อมูลเช่น a List
หรือ a Dictionary
หรืออื่น ๆ หรือแม้กระทั่งในเขตข้อมูลสำรองของผู้รับมอบสิทธิ์ แต่อย่าลืมว่าคุณไม่จำเป็นต้องใช้เขตข้อมูลตัวแทน
เหตุการณ์ใน. net คือชุดค่าผสมที่กำหนดไว้ของวิธีการเพิ่มและวิธีการลบซึ่งทั้งคู่คาดว่าผู้รับมอบสิทธิ์บางประเภทโดยเฉพาะ ทั้ง C # และ vb.net สามารถสร้างรหัสโดยอัตโนมัติสำหรับวิธีการเพิ่มและลบซึ่งจะกำหนดผู้รับมอบสิทธิ์เพื่อเก็บการสมัครสมาชิกของเหตุการณ์และเพิ่ม / ลบรหัสผ่านที่ส่งผ่านใน delegagte ไปยัง / จากผู้รับมอบสิทธิ์การสมัครสมาชิกนั้น VB.net จะสร้างรหัสอัตโนมัติ (พร้อมกับคำสั่ง RaiseEvent) เพื่อเรียกใช้รายการการสมัครหากหากไม่ว่างเปล่า; ด้วยเหตุผลบางอย่าง C # ไม่ได้สร้างสิ่งหลัง
โปรดทราบว่าแม้ว่าจะเป็นเรื่องปกติในการจัดการการสมัครสมาชิกของเหตุการณ์โดยใช้ผู้รับมอบหลายผู้รับนั่นไม่ใช่วิธีเดียวในการทำเช่นนั้น จากมุมมองสาธารณะผู้สมัครสมาชิกกิจกรรมจะต้องทราบวิธีการแจ้งให้วัตถุทราบว่าต้องการรับเหตุการณ์ แต่ไม่จำเป็นต้องรู้ว่ากลไกใดที่ผู้เผยแพร่จะใช้เพื่อเพิ่มเหตุการณ์ โปรดทราบว่าในขณะที่ใครก็ตามที่กำหนดโครงสร้างข้อมูลเหตุการณ์ใน. net คิดว่าควรจะมีวิธีการสาธารณะในการเลี้ยงดูพวกเขาทั้ง C # และ vb.net ไม่ได้ใช้ประโยชน์จากคุณสมบัตินั้น
ในการกำหนดเกี่ยวกับเหตุการณ์ด้วยวิธีง่ายๆ:
เหตุการณ์คือการอ้างอิงถึงตัวแทนที่มีข้อ จำกัด สองประการ
สองข้อข้างต้นเป็นจุดอ่อนสำหรับผู้ได้รับมอบหมายและได้รับการแก้ไขในเหตุการณ์ ตัวอย่างโค้ดที่สมบูรณ์เพื่อแสดงให้เห็นความแตกต่างในไวโอลินอยู่ที่นี่https://dotnetfiddle.net/5iR3fB
สลับความคิดเห็นระหว่างกิจกรรมและผู้รับมอบสิทธิ์และรหัสลูกค้าที่เรียกใช้ / กำหนดค่าเพื่อมอบหมายให้เข้าใจถึงความแตกต่าง
นี่คือรหัสแบบอินไลน์
/*
This is working program in Visual Studio. It is not running in fiddler because of infinite loop in code.
This code demonstrates the difference between event and delegate
Event is an delegate reference with two restrictions for increased protection
1. Cannot be invoked directly
2. Cannot assign value to delegate reference directly
Toggle between Event vs Delegate in the code by commenting/un commenting the relevant lines
*/
public class RoomTemperatureController
{
private int _roomTemperature = 25;//Default/Starting room Temperature
private bool _isAirConditionTurnedOn = false;//Default AC is Off
private bool _isHeatTurnedOn = false;//Default Heat is Off
private bool _tempSimulator = false;
public delegate void OnRoomTemperatureChange(int roomTemperature); //OnRoomTemperatureChange is a type of Delegate (Check next line for proof)
// public OnRoomTemperatureChange WhenRoomTemperatureChange;// { get; set; }//Exposing the delegate to outside world, cannot directly expose the delegate (line above),
public event OnRoomTemperatureChange WhenRoomTemperatureChange;// { get; set; }//Exposing the delegate to outside world, cannot directly expose the delegate (line above),
public RoomTemperatureController()
{
WhenRoomTemperatureChange += InternalRoomTemperatuerHandler;
}
private void InternalRoomTemperatuerHandler(int roomTemp)
{
System.Console.WriteLine("Internal Room Temperature Handler - Mandatory to handle/ Should not be removed by external consumer of ths class: Note, if it is delegate this can be removed, if event cannot be removed");
}
//User cannot directly asign values to delegate (e.g. roomTempControllerObj.OnRoomTemperatureChange = delegateMethod (System will throw error)
public bool TurnRoomTeperatureSimulator
{
set
{
_tempSimulator = value;
if (value)
{
SimulateRoomTemperature(); //Turn on Simulator
}
}
get { return _tempSimulator; }
}
public void TurnAirCondition(bool val)
{
_isAirConditionTurnedOn = val;
_isHeatTurnedOn = !val;//Binary switch If Heat is ON - AC will turned off automatically (binary)
System.Console.WriteLine("Aircondition :" + _isAirConditionTurnedOn);
System.Console.WriteLine("Heat :" + _isHeatTurnedOn);
}
public void TurnHeat(bool val)
{
_isHeatTurnedOn = val;
_isAirConditionTurnedOn = !val;//Binary switch If Heat is ON - AC will turned off automatically (binary)
System.Console.WriteLine("Aircondition :" + _isAirConditionTurnedOn);
System.Console.WriteLine("Heat :" + _isHeatTurnedOn);
}
public async void SimulateRoomTemperature()
{
while (_tempSimulator)
{
if (_isAirConditionTurnedOn)
_roomTemperature--;//Decrease Room Temperature if AC is turned On
if (_isHeatTurnedOn)
_roomTemperature++;//Decrease Room Temperature if AC is turned On
System.Console.WriteLine("Temperature :" + _roomTemperature);
if (WhenRoomTemperatureChange != null)
WhenRoomTemperatureChange(_roomTemperature);
System.Threading.Thread.Sleep(500);//Every second Temperature changes based on AC/Heat Status
}
}
}
public class MySweetHome
{
RoomTemperatureController roomController = null;
public MySweetHome()
{
roomController = new RoomTemperatureController();
roomController.WhenRoomTemperatureChange += TurnHeatOrACBasedOnTemp;
//roomController.WhenRoomTemperatureChange = null; //Setting NULL to delegate reference is possible where as for Event it is not possible.
//roomController.WhenRoomTemperatureChange.DynamicInvoke();//Dynamic Invoke is possible for Delgate and not possible with Event
roomController.SimulateRoomTemperature();
System.Threading.Thread.Sleep(5000);
roomController.TurnAirCondition (true);
roomController.TurnRoomTeperatureSimulator = true;
}
public void TurnHeatOrACBasedOnTemp(int temp)
{
if (temp >= 30)
roomController.TurnAirCondition(true);
if (temp <= 15)
roomController.TurnHeat(true);
}
public static void Main(string []args)
{
MySweetHome home = new MySweetHome();
}
}
ผู้รับมอบสิทธิ์เป็นตัวชี้ฟังก์ชั่นประเภทปลอดภัย เหตุการณ์คือการนำรูปแบบการออกแบบผู้เผยแพร่ - สมาชิกไปใช้โดยใช้ผู้รับมอบสิทธิ์
ถ้าคุณตรวจสอบ Intermediate Language คุณจะรู้ว่า. net compiler แปลงผู้รับมอบสิทธิ์เป็นคลาสที่ปิดผนึกใน IL ด้วยฟังก์ชั่น build-in เช่น invoke, startInvoke, endInvoke และมอบหมายคลาสที่สืบทอดจากคลาสอื่นซึ่งอาจเรียกว่า "SystemMulticast" ฉันเดาว่าอีเวนต์เป็นคลาสย่อยของผู้ได้รับมอบหมายพร้อมคุณสมบัติเพิ่มเติมบางอย่าง
ความแตกต่างระหว่างอินสแตนซ์ของเหตุการณ์และผู้รับมอบสิทธิ์คือคุณไม่สามารถเรียกใช้กิจกรรมนอกการประกาศ หากคุณประกาศเหตุการณ์ในคลาส A คุณสามารถรันกิจกรรมนี้ในคลาส A เท่านั้นหากคุณประกาศผู้รับมอบสิทธิ์ในคลาส A คุณสามารถใช้ผู้รับมอบสิทธิ์นี้ได้ทุกที่ ฉันคิดว่านี่เป็นข้อแตกต่างที่สำคัญระหว่างพวกเขา