C# 在C事件处理程序中,为什么;“发件人”;参数是对象吗?

C# 在C事件处理程序中,为什么;“发件人”;参数是对象吗?,c#,events,C#,Events,根据,C#事件处理程序中的sender参数“始终为object类型,即使可以使用更具体的类型” 这导致了大量事件处理代码,如: RepeaterItem item = sender as RepeaterItem; if (item != null) { /* Do some stuff */ } 为什么约定不建议使用更具体的类型声明事件处理程序 MyType { public event MyEventHander MyEvent; } ... delegate void MyE

根据,C#事件处理程序中的
sender
参数“始终为object类型,即使可以使用更具体的类型”

这导致了大量事件处理代码,如:

RepeaterItem item = sender as RepeaterItem;
if (item != null) { /* Do some stuff */ }
为什么约定不建议使用更具体的类型声明事件处理程序

MyType
{
    public event MyEventHander MyEvent;
}

...

delegate void MyEventHander(MyType sender, MyEventArgs e);
我是不是错过了一个机会

对于后代:我同意答案中的普遍观点,即约定是使用对象(并通过
EventArgs
)传递数据,即使可以使用更具体的类型,在现实编程中遵循约定也很重要


编辑:bait for search:RSPEC-3906规则“事件处理程序应该有正确的签名”

嗯,这是一种模式而不是规则。这确实意味着一个组件可以转发另一个组件的事件,保留原始发送方,即使它不是引发事件的正常类型

我同意这有点奇怪,但为了熟悉起见,遵守惯例可能是值得的。(也就是说,对其他开发人员来说比较熟悉。)我自己从来没有特别热衷于
EventArgs
(因为它本身并不传递任何信息),但这是另一个话题。(至少我们现在有了
EventHandler
——尽管对于只需要传播单个值的常见情况,如果也有
EventArgs
会有所帮助。)


编辑:它确实使委托更通用,当然-单个委托类型可以跨多个事件重用。我不确定我是否认为这是一个特别好的理由——特别是考虑到仿制药——但我想这是一个…

好吧,这是一个好问题。我认为,因为任何其他类型都可以使用您的委托来声明事件,所以您无法确定发送方的类型是否真的是“MyType”。

泛型和历史记录将起到很大作用,特别是对于暴露类似事件的控件(等)的数量。如果没有泛型,您将最终导致大量事件暴露
控件
,这在很大程度上是无用的:

  • 您仍然需要强制转换来执行任何有用的操作(除了可能的引用检查,您可以使用
    对象
    执行该检查)
  • 您不能在非控件上重复使用事件

如果我们考虑泛型,那么所有的都是好的,但是你开始进入继承的问题;如果类

B:A
,那么
A
上的事件应该是
EventHandler
,而
B
上的事件应该是
EventHandler
?同样,非常混乱,很难使用工具,而且在语言方面有点混乱


除非有更好的选项涵盖所有这些,否则,
object
会起作用;事件几乎总是在类实例上,因此没有装箱等,只有一个演员阵容。而且施法也不是很慢。

我想这是因为你应该能够做到

void SomethingChanged(object sender, EventArgs e) {
    EnableControls();
}
...
MyRadioButton.Click += SomethingChanged;
MyCheckbox.Click += SomethingChanged;
...

为什么要在代码中执行安全强制转换?如果您知道只将函数用作中继器的事件处理程序,则您知道参数的类型始终正确,并且可以使用抛出转换,例如(中继器)发送器而不是(发送器作为中继器)。

存在的约定仅用于强制一致性

如果愿意,您可以强式地键入事件处理程序,但请自问这样做是否会带来任何技术优势

你应该考虑事件处理程序并不总是需要发送发送器…我在实际操作中看到的大多数事件处理代码都没有使用sender参数。如果需要它,它就在那里,但通常不是

我经常看到不同对象上的不同事件共享一个公共事件处理程序的情况,这是因为该事件处理程序与发送者无关

如果这些委托是强类型的,即使巧妙地使用泛型,也很难共享这样的事件处理程序。事实上,通过强输入它,你强加了一个假设,即处理程序应该关心发送者是什么,而这不是实际情况

我想您应该问的是,为什么要强烈地键入事件处理代理?这样做是否会增加任何显著的功能优势?你是否使用法更加“一致”?或者你只是为了强输入而强加假设和约束?

你说:

这会导致大量的事件处理 代码如下:-

它真的有很多代码吗

我建议不要对事件处理程序使用
sender
参数。正如您所注意到的,它不是静态类型的。它不一定是事件的直接发送者,因为有时会转发事件。因此,每次触发同一事件处理程序时,它甚至可能不会获得相同的
sender
对象类型。这是一种不必要的隐式耦合形式

当您登记某个事件时,此时您必须知道该事件所在的对象,而这正是您最感兴趣的对象:

someControl.Exploded += (s, e) => someControl.RepairWindows();
而任何特定于该事件的其他内容都应该在EventArgs派生的第二个参数中

基本上,
sender
参数是一点历史噪音,最好避免


这是因为你永远无法确定是谁触发了事件。无法限制允许触发特定事件的类型。

使用EventHandler(对象发送方,EventArgs e)的模式旨在为所有事件提供标识事件源(发送方)的方法,并为所有事件的特定负载提供容器。 此模式的优点还在于,它允许使用相同类型的委托生成许多不同的事件

至于此默认委托的参数。。。 你想在活动中传递的所有州都有一个包,这样做的好处是公平的
someControl.Exploded += (s, e) => someControl.RepairWindows();
Foo foo = sender as Foo;
if (foo !=null) { ... }
/// <summary>
/// Delegate used to handle events with a strongly-typed sender.
/// </summary>
/// <typeparam name="TSender">The type of the sender.</typeparam>
/// <typeparam name="TArgs">The type of the event arguments.</typeparam>
/// <param name="sender">The control where the event originated.</param>
/// <param name="e">Any event arguments.</param>
public delegate void EventHandler<TSender, TArgs>(TSender sender, TArgs e) where TArgs : EventArgs;
public event EventHandler<TypeOfSender, TypeOfEventArguments> CustomEvent;
void SomethingChanged(object sender, EventArgs e) {
    EnableControls();
}
...
MyRadioButton.Click += SomethingChanged;
MyCheckbox.Click += SomethingChanged;
MyDropDown.SelectionChanged += SomethingChanged;
...
//this won't work
GallowayClass.Changed += SomethingChanged;