题
我目前具有hardtime了解和实施的事件C#使用delagates.我用来Java的方式做事情:
- 定义一界面为一个监听器类型,其中将包括一些方法的定义
- 定义适配器类界面,使事情变得更容易,如果我不感兴趣的所有事件中定义的听众
- 定义中添加、删除和获取[]方法的类引起的活动
- 定义保护防火方法做肮脏的工作的循环,通过列表中添加的听众并呼吁的正确方法
这我理解(以及喜欢!) -我知道我可以这样做完全相同,但它似乎是一个新的(更好的?) 系统中的地方。在阅读了无数的教程说明所使用的代表和事件c#我还是我没有更接近真正理解什么是:S
在短期,对下列方法如何将我实现的事件系统在c#:
void computerStarted(Computer computer);
void computerStopped(Computer computer);
void computerReset(Computer computer);
void computerError(Computer computer, Exception error);
^上述方法是采取从Java应我一旦做了我想要口交给c#。
许多许多的感谢!
解决方案
你会创建的四个事件,和方法,以提高他们,随着一个新的定引基于类指示的错误:
public class ExceptionEventArgs : EventArgs
{
private readonly Exception error;
public ExceptionEventArgs(Exception error)
{
this.error = error;
}
public Error
{
get { return error; }
}
}
public class Computer
{
public event EventHandler Started = delegate{};
public event EventHandler Stopped = delegate{};
public event EventHandler Reset = delegate{};
public event EventHandler<ExceptionEventArgs> Error = delegate{};
protected void OnStarted()
{
Started(this, EventArgs.Empty);
}
protected void OnStopped()
{
Stopped(this, EventArgs.Empty);
}
protected void OnReset()
{
Reset(this, EventArgs.Empty);
}
protected void OnError(Exception e)
{
Error(this, new ExceptionEventArgs(e));
}
}
课程将然后订购的事件使用的方法或一个匿名的功能:
someComputer.Started += StartEventHandler; // A method
someComputer.Stopped += delegate(object o, EventArgs e)
{
Console.WriteLine("{0} has started", o);
};
someComputer.Reset += (o, e) => Console.WriteLine("{0} has been reset");
有几件事要注意的有关上述:
- 该OnXXX方法都受到保护,以便得出类可以提高的活动。这并不总是有必要的-这样做,你认为合适。
- 的
delegate{}
片上的每个事件的宣言只是一种欺骗,以避免不必做一个空检查。这是订阅一个没有运事件的处理程序每个事件 - 该事件的声明 现场-像事件.什么是实际上正在创建这两个变量 和 一个事件。内部流的你看到的变量;该类的外部你看到的事件。
看到我的 事/代表 文章更加详细的事件。
其他提示
你就必须限定一个单一的委托,
public delegate void ComputerEvent(object sender, ComputerEventArgs e);
ComputerEventArgs将定义的这样的:
public class ComputerEventArgs : EventArgs
{
// TODO wrap in properties
public Computer computer;
public Exception error;
public ComputerEventArgs(Computer aComputer, Exception anError)
{
computer = aComputer;
error = anError;
}
public ComputerEventArgs(Computer aComputer) : this(aComputer, null)
{
}
}
这类火灾事件,将这些:
public YourClass
{
...
public event ComputerEvent ComputerStarted;
public event ComputerEvent ComputerStopped;
public event ComputerEvent ComputerReset;
public event ComputerEvent ComputerError;
...
}
这是你如何分配处理程序的活动:
YourClass obj = new YourClass();
obj.ComputerStarted += new ComputerEvent(your_computer_started_handler);
你的处理程序是:
private void ComputerStartedEventHandler(object sender, ComputerEventArgs e)
{
// do your thing.
}
首先,有一个标准的方法的签名。净是通常用于事件。的语言允许任何形式的签名方法在所有可用的事件,并有一些专家认为,《公约》是有缺陷的(我同意),但它是它是什么,我将遵循为这个例子。
- 创建一个类将包含的事件的参数(从定引).
public class ComputerEventArgs : EventArgs { Computer computer; // constructor, properties, etc. }
- 创建一个公共事件上的类火的事件。
class ComputerEventGenerator // I picked a terrible name BTW. { public event EventHandler<ComputerEventArgs> ComputerStarted; public event EventHandler<ComputerEventArgs> ComputerStopped; public event EventHandler<ComputerEventArgs> ComputerReset; ... }
- 呼叫的事件。
class ComputerEventGenerator { ... private void OnComputerStarted(Computer computer) { EventHandler<ComputerEventArgs> temp = ComputerStarted; if (temp != null) temp(this, new ComputerEventArgs(computer)); // replace "this" with null if the event is static } }
- 附加一个处理程序的事件。
void OnLoad() { ComputerEventGenerator computerEventGenerator = new ComputerEventGenerator(); computerEventGenerator.ComputerStarted += new EventHandler<ComputerEventArgs>(ComputerEventGenerator_ComputerStarted); }
- 创建处理程序你只是附(主要是通过按标签的关键在VS)。
private void ComputerEventGenerator_ComputerStarted(object sender, ComputerEventArgs args) { if (args.Computer.Name == "HAL9000") ShutItDownNow(args.Computer); }
- 不要忘了分开处理程序,当你完成。(忘记做这是最大的来源,存在泄漏C#!)
void OnClose() { ComputerEventGenerator.ComputerStarted -= ComputerEventGenerator_ComputerStarted; }
这就是它!
编辑:老实说,我不明白为什么我的编号分都显示为"1"。 我讨厌计算机。
有几种方法做你想要什么。的 最直接的 办法将是界定代表为每个事件在托管流,例如
public delegate void ComputerStartedDelegate(Computer computer);
protected event ComputerStartedDelegate ComputerStarted;
public void OnComputerStarted(Computer computer)
{
if (ComputerStarted != null)
{
ComputerStarted.Invoke(computer);
}
}
protected void someMethod()
{
//...
computer.Started = true; //or whatever
OnComputerStarted(computer);
//...
}
任何目的可以"听"对于这种事件只是通过:
Computer comp = new Computer();
comp.ComputerStarted += new ComputerStartedDelegate(
this.ComputerStartedHandler);
protected void ComputerStartedHandler(Computer computer)
{
//do something
}
的'推荐标准的方式',这样做将是定义的一个亚类的定引举行的计算机(和/旧的新的状态和例外)的价值(s),减少了4名代表之一。在这种情况下,这将是一个更清洁的解决方案,esp。与枚举对于计算机的国家的情况下以后的扩展。但是基本的技术仍然是相同的:
- 代理限定的签字/接口的事件处理/监听器
- 事件数据成员名单的听众
听众是使用除去的-=语法,而不是+=
C#活动是代表。他们的行为方式类似功能的指针在C/C++但是实际类源自的系统。代表。
在这种情况下,创建一个自定义定引级通过计算机对象。
public class ComputerEventArgs : EventArgs
{
private Computer _computer;
public ComputerEventArgs(Computer computer) {
_computer = computer;
}
public Computer Computer { get { return _computer; } }
}
然后露出的事件从生产者:
public class ComputerEventProducer
{
public event EventHandler<ComputerEventArgs> Started;
public event EventHandler<ComputerEventArgs> Stopped;
public event EventHandler<ComputerEventArgs> Reset;
public event EventHandler<ComputerEventArgs> Error;
/*
// Invokes the Started event */
private void OnStarted(Computer computer) {
if( Started != null ) {
Started(this, new ComputerEventArgs(computer));
}
}
// Add OnStopped, OnReset and OnError
}
消费者的活动,然后结合的处理程序功能上的每个事件的消费者。
public class ComputerEventConsumer
{
public void ComputerEventConsumer(ComputerEventProducer producer) {
producer.Started += new EventHandler<ComputerEventArgs>(ComputerStarted);
// Add other event handlers
}
private void ComputerStarted(object sender, ComputerEventArgs e) {
}
}
当ComputerEventProducer呼吁OnStarted的事件开始被调用,这反过来将调ComputerEventConsumer.ComputerStarted方法。
该代表声明了一个函数的签名,并且当它是作为一个事件上的一课,它也可作为收集登记的呼吁的目标。该+=及-=语法事件上是用来增加一个目标的名单。
给出下列代表用作活动:
// arguments for events
public class ComputerEventArgs : EventArgs
{
public Computer Computer { get; set; }
}
public class ComputerErrorEventArgs : ComputerEventArgs
{
public Exception Error { get; set; }
}
// delegates for events
public delegate void ComputerEventHandler(object sender, ComputerEventArgs e);
public delegate void ComputerErrorEventHandler(object sender, ComputerErrorEventArgs e);
// component that raises events
public class Thing
{
public event ComputerEventHandler Started;
public event ComputerEventHandler Stopped;
public event ComputerEventHandler Reset;
public event ComputerErrorEventHandler Error;
}
你想订阅这些事件如下:
class Program
{
static void Main(string[] args)
{
var thing = new Thing();
thing.Started += thing_Started;
}
static void thing_Started(object sender, ComputerEventArgs e)
{
throw new NotImplementedException();
}
}
虽然参数可能是任何东西,目的发件人和定引e是《公约》中使用的非常一致。该+=thing_started将首先创建的一个实例,该代表指向目标的方法,然后将它添加到该事件。
关于组件本身通常会增加方法,以火的事件:
public class Thing
{
public event ComputerEventHandler Started;
public void OnStarted(Computer computer)
{
if (Started != null)
Started(this, new ComputerEventArgs {Computer = computer});
}
}
你必须测试空的情况下,没有代表已加入的事件。当你呼叫的方法,但是所有与会代表已加入将被称为。这就是为什么对事件的回报类型的空隙-那里是没有一个单一的返回值所反馈信息将有属性的定引该事件的处理程序将有修改。
另一个改进是使用通用处委托,而不是宣布一个具体委托对于各种类型的args.
public class Thing
{
public event EventHandler<ComputerEventArgs> Started;
public event EventHandler<ComputerEventArgs> Stopped;
public event EventHandler<ComputerEventArgs> Reset;
public event EventHandler<ComputerErrorEventArgs> Error;
}
谢谢你有这么多对于你的答案!最后我开始明白到底是怎么回事。只是一回事;看来,如果每个事件有一个不同的号/种类型的论点,我们需要创建一个不同的::定引级处理:
public void computerStarted(Computer computer);
public void computerStopped(Computer computer);
public void computerReset(Computer computer);
public void breakPointHit(Computer computer, int breakpoint);
public void computerError(Computer computer, Exception exception);
这将需要三个classses处理的事件!?(井两个自定义,以及一个使用默认定引.空类)
干杯!
好吧,最后澄清!:因此,这几乎是我能做到最好的代码-聪明执行这些活动?
public class Computer {
public event EventHandler Started;
public event EventHandler Stopped;
public event EventHandler Reset;
public event EventHandler<BreakPointEvent> BreakPointHit;
public event EventHandler<ExceptionEvent> Error;
public Computer() {
Started = delegate { };
Stopped = delegate { };
Reset = delegate { };
BreakPointHit = delegate { };
Error = delegate { };
}
protected void OnStarted() {
Started(this, EventArgs.Empty);
}
protected void OnStopped() {
Stopped(this, EventArgs.Empty);
}
protected void OnReset() {
Reset(this, EventArgs.Empty);
}
protected void OnBreakPointHit(int breakPoint) {
BreakPointHit(this, new BreakPointEvent(breakPoint));
}
protected void OnError(System.Exception exception) {
Error(this, new ExceptionEvent(exception));
}
}
}