当处理事件时需要显式的委托声明
本文关键字:声明 处理事件 | 更新日期: 2023-09-27 18:16:33
我们只知道委托是函数指针。所以当我们处理事件时,我们声明委托但我想知道在哪种情况下我们必须声明委托当处理像public delegate void OnButtonClickDelegate();
这里我引用了一个代码示例,显示我们可以使用内置委托EventHandler
而不是显式声明委托。
public class ArgsSpecial : EventArgs
{
public ArgsSpecial (string val)
{
Operation=val;
}
public string Operation {get; set;}
}
public class Animal
{
// Empty delegate. In this way you are sure that value is always != null
// because no one outside of the class can change it.
public event EventHandler<ArgsSpecial> Run = delegate{}
public void RaiseEvent()
{
Run(this, new ArgsSpecial("Run faster"));
}
}
Animale animal= new Animal();
animal.Run += (sender, e) => Console.WriteLine("I'm running. My value is {0}", e.Operation);
animal.RaiseEvent();
所以当EventHandler
在内置委托解决我的目的,然后我们不需要声明委托时,与事件工作。所以告诉我在哪里我们必须明确声明委托,EventHandler
可能无法解决我们的目的。由于
EventHandler
实际上有一个非常有限的签名,两个参数,其中第一个总是类型object
,第二个必须是继承System.EventArgs
的类类型。但是考虑到System.Action<T, ...>
和System.Func<T, ..., TReturn>
,您很少需要声明另一个。事实上,如果当时存在Action和Func家族,那么大多数最初的BCL委托类型MethodInvoker
、Converter<T, U>
、Predicate<T>
甚至EventHandler<T>
可能都不会被定义。
当你需要引用参数时,你仍然需要声明你自己的委托。ref
和out
关键字不能通过泛型类型参数传递,所以如果你想要一个与TryParse
家族匹配的委托,你就不能说Func<string, out T, bool>
,需要一个自定义声明
/* return true if parsing successful */
delegate bool TryParser<T>(string from, out T into);
在事件中使用引用参数是很少见的,所以你可能永远不需要声明一个委托作为事件类型使用。
如果您希望事件接收EventHandler
指定的参数以外的参数,则需要自定义委托
例如,假设你的Animal
类想要在每次另一个Animal
试图吃掉它时引发一个事件,这个事件可能需要发送捕食者和被攻击的动物。使用EventHandler
,您需要创建一个新类作为两个动物的包装器,并将其实例作为事件参数发送,使用委托更简单:
public delegate void AttackedDelegate(Animal predator, Animal victim);
//...
public event AttackedDelegate OnAttacked;
虽然引入了Action<>
委托,但我认为除了可读性之外,您需要声明自己的委托的情况要少得多。所以上面的例子可以表示为
public event Action<Animal, Animal> OnAttacked;