当处理事件时需要显式的委托声明

本文关键字:声明 处理事件 | 更新日期: 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委托类型MethodInvokerConverter<T, U>Predicate<T>甚至EventHandler<T>可能都不会被定义。

当你需要引用参数时,你仍然需要声明你自己的委托。refout关键字不能通过泛型类型参数传递,所以如果你想要一个与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;