C# 代表和活动之间有什么区别?
代表和活动之间有什么区别?这两个函数是否都包含对可以执行的函数的引用?一个事件声明在委托实例上添加了一层抽象和保护。此保护可防止委托的客户端重置委托及其调用列表,并且仅允许从调用列表中添加或删除目标。除了语法和操作属性之外,还有语义差异 从概念上讲,委托是功能模板;也就是说,它们表示一个函数必须遵守的契约,才能被视为委托的“类型”C# 代表和活动之间有什么区别?,c#,events,delegates,glossary,C#,Events,Delegates,Glossary,代表和活动之间有什么区别?这两个函数是否都包含对可以执行的函数的引用?一个事件声明在委托实例上添加了一层抽象和保护。此保护可防止委托的客户端重置委托及其调用列表,并且仅允许从调用列表中添加或删除目标。除了语法和操作属性之外,还有语义差异 从概念上讲,委托是功能模板;也就是说,它们表示一个函数必须遵守的契约,才能被视为委托的“类型” private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { Media
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`.
}
事件代表。。。嗯,事件。它们用于在发生事件时提醒某人,是的,它们遵守委托定义,但它们不是同一件事
即使它们是完全相同的东西(语法上和IL代码中),仍然会存在语义上的差异。一般来说,我更喜欢为两个不同的概念使用两个不同的名称,即使它们是以相同的方式实现的(这并不意味着我喜欢使用相同的代码两次)。您也可以在接口声明中使用事件,而不是委托。在.net中的事件是Add方法和Remove方法的指定组合,两者都需要某种特定类型的委托。C#和vb.net都可以为add和remove方法自动生成代码,这些方法将定义一个用于保存事件订阅的委托,并向该订阅委托添加/删除传入的delegate。当且仅当订阅列表非空时,VB.net还将自动生成代码(使用RaiseEvent语句)来调用订阅列表;出于某种原因,C#不会生成后者
请注意,虽然使用多播委托管理事件订阅很常见,但这并不是唯一的方法。从公共角度来看,潜在的事件订阅者需要知道如何让对象知道它想要接收事件,但不需要知道发布者将使用什么机制来引发事件。还要注意的是,尽管在.net中定义事件数据结构的人显然认为应该有一种公开的方法来提高它们,但C#和vb.net都没有利用该功能。这里是另一个很好的链接。 简而言之,文章中的事件是对委托的封装 引自文章: 假设事件在C#/.NET中不作为一个概念存在。另一个类如何订阅事件?三种选择:
要了解这些差异,您可以看看这两个示例 委托示例(在本例中,是一个操作,它是一种不返回值的委托) 要使用委托,应执行以下操作:
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
类的每个类都可以直接调用委托。例如,animal.Run()
或animal.Run.Invoke()
在动物类之外有效
为了避免这些弱点,可以在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.Run()
或animal.Run.Invoke()
在animal类之外无效,并将产生编译器错误public delegate void EventHandler (object sender, EventArgs e)
它接受发送方(对象类型)和事件参数。如果发送方来自静态方法,则该发送方为null
这个例子使用了
EventHandler来记录EventHandler事件和委托之间的巨大误解!!!委托指定一种类型(例如类
,或接口
),而事件只是一种成员(例如字段、属性等)。而且,就像任何其他类型的成员一样,事件也有一个类型。但是,对于事件,事件的类型必须由委托指定。例如,不能声明由接口定义的类型的事件
最后,我们可以使
public delegate void EventHandler (object sender, EventArgs e)
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;
}
}
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`.
}
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 });
}
}
}
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;
}
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
Mediator.GetInstance().OnPersonChanged(this, (Person)comboBox1.SelectedItem);
}
class PersonChangedEventArgs
{
public Person Person { get; set; }
}
/*
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();
}
}
// eventTest.SomeoneSay = null; // Compile Error.
// eventTest.SomeoneSay = new Say(SayHello); // Compile Error.
public class DelegateTest
{
public delegate void Say(); // Define a pointer type "void <- ()" named "Say".
private Say say;
public DelegateTest() {
say = new Say(SayHello); // Setup the field, Say say, first.
say += new Say(SayGoodBye);
say.Invoke();
}
public void SayHello() { /* display "Hello World!" to your GUI. */ }
public void SayGoodBye() { /* display "Good bye!" to your GUI. */ }
}
public class EventTest
{
public delegate void Say();
public event Say SomeoneSay; // Use the type "Say" to define event, an
// auto-setup-everything-good field for you.
public EventTest() {
SomeoneSay += SayHello;
SomeoneSay += SayGoodBye;
SomeoneSay();
}
public void SayHello() { /* display "Hello World!" to your GUI. */ }
public void SayGoodBye() { /* display "Good bye!" to your GUI. */ }
}