事件处理程序<T> 和事件处理程序
EventHandler<T> and EventHandler
我想问一下EventHandler
和EventHandler<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
的通用变体。通常,您会覆盖 EventArgs
和 EventHandler
以得出自己的事件类型。如果您想将自定义属性传递给 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
.
时,这正是您所做的
我想问一下EventHandler
和EventHandler<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
的通用变体。通常,您会覆盖 EventArgs
和 EventHandler
以得出自己的事件类型。如果您想将自定义属性传递给 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
.