事件处理程序<T> 和事件处理程序

EventHandler<T> and EventHandler

我想问一下EventHandlerEventHandler<T>的区别。

之前我已经实现了一个 EventHandler,带有一个可以从用户控件传递到父页面的自定义 EventArgs。

我以为我需要申请EventHandler< T >,但是可以使用EventHandler来实现。 (事实上​​ ,当我尝试应用 EventHandler<T> 时出现了奇怪的错误,程序运行正常但错误显示在 IDE 中,我无法解决 [C# Custom EventHandler ])

所以我想知道在什么情况下需要申请EventHandler < T >?

public event EventHandler AppendProcess;
public event EventHandler<MyEventArg> AppendProcess;

---更新--- 这就是我在用户控件中调用事件的方式(正如我所说,我可以通过这样做将对象传递给父页面(虽然我不知道这样做是否正确)

if (AppendProcess == null) { }
else
    AppendProcess(this, new Common.WinLose_ProgressStage(Common.WinLose_SP_Parameter.upper, displayLevel + 1, 
                                                            (int)Common.WinLose_Level.lvChild4, thename, refundratio, 
                                                            selfproportion, -1, -1, loadlevel, isPlayer, betsource, gamecategory, false));

EventHandler<T> 只是一个通用的 EventHandler 类型,这样您就不必为要使用的每种 EventArgs 声明一个新的委托类型。

考虑 Control.KeyPress for example. It's declared as an event of type KeyPressEventHandler。该代表刚刚声明为:

public delegate void KeyPressEventHandler(object sender, KeyPressEventArgs e)

如果 EventHandler<T>(和泛型)在创建时已经存在,则可以将事件声明为 EventHandler<KeyPressEventArgs>,从而保存委托声明。有很多很多像 EventHandler 一样的委托,只是第二个参数的类型有所不同 - EventHandler<T> 避免了冗余。

不,如果您没有 自己的自定义 EventArgs 子类,则没有理由使用 EventHandler<T>...但是如果您有,使用它要好得多,这样方法 handling 事件以强类型的方式接收您的自定义 EventArgs 子类。

顺便说一句,您调用事件处理程序的方式不是线程安全的。另一个线程可以取消订阅最终事件处理程序 您的无效检查之后。如果您使用的是 C# 5,则应将其写为:

var handler = AppendProcess;
if (handler != null)
{
    handler(this, new Common.WinLose_ProgressStage(...));
}

如果您使用的是 C# 6 或更高版本,则可以使用 null 条件运算符:

// If AppendProcess is null, the arguments won't even be evaluated
AppendProcess?.Invoke(this, new Common.WinLose_ProgressStage(...));

EventHandler<T>EventHandler 的通用变体。通常,您会覆盖 EventArgsEventHandler 以得出自己的事件类型。如果您想将自定义属性传递给 e 参数,您仍然需要派生 EventArgs,但您不再需要为 EventHandler 创建自定义委托。你现在可以说:

public event EventHandler<SomeEventArgs> SomeEvent;

哪个比

更方便
public delegate void SomeEventHandler(object sender, SomeEventArgs e);

public event SomeEventHandler SomeEvent;

当您的委托签名不变时,EventHandler<T> 更易于使用。

来自你的另一个问题:

Common.WinLose_ProgressStage wps = (Common.WinLose_ProgressStage)e;

这是一个可能会失败的转换,具体取决于调用方法的方式。没有什么可以保证您的事件处理程序只会被调用 Common.WinLose_ProgressStage 可以在不检查完整程序的情况下进行检查。它也可以用普通的 EventArgs 来调用:您通过将参数类型设置为 EventArgs.

来实现这一点

EventHandler<T> 导致更多的编译时类型检查。如果其他代码试图传入 EventArgs.Empty,调用将无法编译。

和"why shouldn't I make all my parameters of type object"基本一样?当然,你可以这样做。如果你这样做,在需要的地方回退,你的代码就会工作。但我知道我更喜欢

long Add(long x, long y) { return x + y; }

超过

object Add(object x, object y) { return (long)x + (long)y; }

而且我怀疑在这种情况下,您也是如此。然而,当您将参数类型设置为 EventArgs 而不是 Common.WinLose_ProgressStage.

时,这正是您所做的