C# 委托与 EventHandler
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18170282/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# delegate v.s. EventHandler
提问by Hsu Wei Cheng
I want to send an alert message to any subscribers when a trap occurred.
我想在发生陷阱时向任何订阅者发送警报消息。
The code I created works fine using a delegate method myDelegate del
.
我创建的代码使用委托方法可以正常工作myDelegate del
。
My questions are:
我的问题是:
I want to know whether it's better to use
EventHandler
instead of a delegate? I'm not sure what the differences are between a delegate and anEventHandler
in my case.notify(trapinfo t)
, that's what I've done here to get trap information. But it seems not to be a good idea. I read some online tutorial lesson introducing passing delegate object; I'm wondering if it's appropriate in my case? And how should I do it? Any suggestions?
我想知道使用
EventHandler
代理是否更好?我不确定EventHandler
在我的情况下委托和委托之间有什么区别。notify(trapinfo t)
,这就是我在这里所做的以获取陷阱信息。但这似乎不是一个好主意。我阅读了一些介绍传递委托对象的在线教程;我想知道它是否适合我的情况?我该怎么做?有什么建议?
Thanks a lot :)
非常感谢 :)
My code:
我的代码:
public class trapinfo
{
public string info;
public string ip;
public string cause;
}
public class trap
{
public delegate void myDelegate(trapinfo t);
public myDelegate del;
trapinfo info = new trapinfo();
public void run()
{
//While(true)
// If a trap occurred, notify the subscriber
for (; ; )
{
Thread.Sleep(500);
foreach (myDelegate d in del.GetInvocationList())
{
info.cause = "Shut Down";
info.ip = "192.168.0.1";
info.info = "Test";
d.Invoke(info);
}
}
}
}
public class machine
{
private int _occuredtime=0;
public trapinfo info = new trapinfo();
public void notify(trapinfo t)
{
++_occuredtime;
info.cause = t.cause;
info.info = t.info;
info.ip = t.ip;
getInfo();
}
public void subscribe(trap t)
{
t.del += new trap.myDelegate(notify);
}
public void getInfo()
{
Console.WriteLine("<Alert>: cauese/{0}, info/ {1}, ip/{2}, time/{3}",
info.cause, info.info, info.ip,_occuredtime);
}
}
class Program
{
static void Main(string[] args)
{
trap t = new trap();
machine machineA = new machine();
machineA.subscribe(t);
t.run();
}
}
Update 2013-08-12
更新 2013-08-12
How about the observer/observabledesign pattern, that looks great in my case (EventHandler
).
观察者/可观察设计模式怎么样,在我的情况下看起来很棒(EventHandler
)。
In my case, a machine subscribes to a trap messenger. (Add a machine to an invocation list)
Once a trap occurred, I send a message to all machines which are subscribed. (Call HandleEvent
to handle it)
就我而言,一台机器订阅了一个陷阱信使。(将机器添加到调用列表)一旦发生陷阱,我会向所有订阅的机器发送消息。(打电话HandleEvent
处理)
Advantages:
好处:
don't care about
GetInvocationList()
anymore, just use(+=)
and(-=)
to decide whom to send the trap.It's easier to understand the logic of my program.
不用管
GetInvocationList()
了,就用(+=)
和(-=)
决定把陷阱发给谁。更容易理解我的程序的逻辑。
I know there are several ways to do it, but I wish I could analyze its pros and cons.
我知道有几种方法可以做到这一点,但我希望我能分析一下它的利弊。
And thanks for your comments and suggestions, that would be very helpful!
并感谢您的意见和建议,这将非常有帮助!
I read the MSDN EventArgsarticle which Matthew Watson suggested.
我阅读了Matthew Watson 建议的MSDN EventArgs文章。
Here's my Event Version:
这是我的活动版本:
public class TrapInfoEventArgs : EventArgs
{
public int info { get; set; }
public string ip { get; set; }
public string cause { get; set; }
}
public class trap
{
public event EventHandler<TrapInfoEventArgs> TrapOccurred;
protected virtual void OnTrapOccurred(TrapInfoEventArgs e)
{
EventHandler<TrapInfoEventArgs> handler = TrapOccurred;
if (handler != null)
{
handler(this, e);
}
}
public void run()
{
//While(true)
// If a trap occurred, notify the subscriber
for (; ; )
{
Thread.Sleep(500);
TrapInfoEventArgs args = new TrapInfoEventArgs();
args.cause = "Shut Down";
OnTrapOccurred(args);
}
}
}
public class machine
{
public void c_TrapOccurred(object sender, TrapInfoEventArgs e)
{
Console.WriteLine("<Alert>: cauese/{0}, info/ {1}, ip/{2}, time/{3}",
e.cause, e.info, e.ip, DateTime.Now.ToString());
}
}
class Program
{
static void Main(string[] args)
{
trap t = new trap();
machine machineA = new machine();
t.TrapOccurred += machineA.c_TrapOccurred; //notify machine A
t.run();
}
}
采纳答案by qwr
The difference between event and delegate is that:
事件和委托的区别在于:
event declaration adds a layer of protection on the delegate instance. This protection prevents clients of the delegate from resetting the delegate and its invocation list, and only allows adding or removing targets from the invocation list
事件声明为委托实例增加了一层保护。此保护可防止委托的客户端重置委托及其调用列表,并且仅允许从调用列表中添加或删除目标
See What are the differences between delegates and events?
2) As I see it, your subscriber should not change delegates freely. One subscriber can assign =
to it instead of adding +=
. This will assign a new delegate, therefore, the previous delegate with its invocation list will be lost and previous subscribers will not be called anymore. So you should use Event for sure. Or you can change your code to make your delegate private and write additional functions for manipulating it to define your own event behavior.
2)据我所知,您的订阅者不应随意更改代表。一个订阅者可以分配=
给它而不是添加+=
。这将分配一个新的委托,因此,先前的委托及其调用列表将丢失,并且不再调用先前的订阅者。所以你肯定应该使用 Event 。或者您可以更改您的代码以将您的委托设为私有并编写额外的函数来操作它以定义您自己的事件行为。
//preventing direct assignment
private myDelegate del ;
public void AddCallback(myDelegate m){
del += m;
}
public void RemoveCallback(myDelegate m){
del -= m;
}
//or
public static trap operator +(trap x,myDelegate m){
x.AddCallback(m);
return x;
}
public static trap operator -(trap x, myDelegate m)
{
x.RemoveCallback(m);
return x;
}
//usage
//t.AddCallback(new trap.myDelegate(notify));
t+=new trap.myDelegate(notify);
回答by Matthew Watson
It is much better to use an event
for your example.
最好使用 anevent
作为您的示例。
An
event
is understood by the Visual Studio Form and WPF designers, so you can use the IDE to subscribe to events.When raising
events
, there is no need for you to write your ownforeach
handling to iterate through them.events
are the way that most programmers will expect this functionality to be accessed.If you use a delegate, the consuming code can mess around with it in ways that you will want to prevent (such as resetting its invocation list).
events
do not allow that to happen.
event
Visual Studio 窗体和 WPF 设计器理解An ,因此您可以使用 IDE 订阅事件。在提高 时
events
,您无需编写自己的foreach
处理来遍历它们。events
是大多数程序员期望访问此功能的方式。如果您使用委托,则使用代码可能会以您希望阻止的方式(例如重置其调用列表)来干扰它。
events
不允许这种情况发生。
As for your second question: Using an event
you would create a class derived from EventArgs
to hold the data, and pass that to the event when you raise it. The consumer will then have access to it.
至于你的第二个问题:使用 anevent
你会创建一个派生自的类EventArgs
来保存数据,并在你引发它时将其传递给事件。然后消费者将可以访问它。
See here for details: http://msdn.microsoft.com/en-us/library/system.eventargs.aspx
有关详细信息,请参见此处:http: //msdn.microsoft.com/en-us/library/system.eventargs.aspx