【问题标题】:C# Delegates and method signaturesC# 委托和方法签名
【发布时间】:2011-06-18 12:32:06
【问题描述】:

来自MSDN

任何与委托匹配的方法 签名,其中包括 返回类型和参数,可以是 分配给委托人。

这怎么可能:

public delegate void AlarmEventHandler(object sender, EventArgs e);
public event AlarmEventHandler Alarm;

protected virtual void OnAlarm(EventArgs e)
        {
            AlarmEventHandler handler = Alarm;
            if (handler != null)
            {
                // Invokes the delegates.
                handler(this, e);
            }
        }

委托AlarmEventHander 和事件AlarmEventHandler 具有不同的签名,但handler 可以分配给Alarm

也许我在某种程度上误解了代表,如果有人能解释我哪里出错了,我将不胜感激。

【问题讨论】:

  • 我认为您混淆了一些符号名称。在上面的代码中,委托被称为AlarmEventHandler,同类型的事件被称为Alarm。由于它们属于同一类型,因此分配没有问题。我认为让您感到困惑的是OnAlarm 方法,它可能会以不同的委托类型响应不同的事件。
  • 我没有看到这里的问题。类型完全匹配(两者都是AlarmEventHandler),因此人们希望能够将一种分配给另一种。

标签: c# delegates


【解决方案1】:

委托就像一个班级。事件就像财产。当你在一个类中声明一个event 时,你声明了它是事件的type。在这种情况下,AlarmEventHandler,它是它所属的顶级类的内部类

OnAlarm 方法中,您获取已分配给事件的AlarmEventHandler 类的实例,并调用它。

为了清楚起见,您上面的代码与此类似,使用普通类和引用:

public class InnerClass {
    public void MyMethod() { /* ... */ }
}

public InnerClass MyProperty { get; set; }

protected virtual void CallMyMethod() {
    InnerClass cls = MyProperty;
    if (cls != null)
        cls.MyMethod();
}

【讨论】:

  • 我喜欢你解释它的方式。它让我想象它如何更好地工作
【解决方案2】:

其实签名是一样的。在 .NET 中,事件是通过委托实现的。

public event AlarmEventHandler Alarm;

所以上面的代码实际上被编译器编译为:

private AlarmEventHandler handler;

public event AlarmEventHandler Alarm
{
    add { handler += value; }
    remove { handler -= value; }
}

所以事件实际上使用了相同的 AlarmEventHandler 委托。

【讨论】:

    【解决方案3】:
    1. 您正在混合代理和事件。虽然事件依赖于委托,但它们完全是不同的概念。所以应该分开服用。
    2. 委托类似于类型定义。使用此委托的地方就像变量或属性。
    3. 事件使该委托的行为与外部不同。签名还是一样的。

    【讨论】:

      【解决方案4】:

      事件只是一个委托。委托本身只能从类内部访问。 从外面看,只有 addremove 功能对事件是可能的,你只能这样做:

      myAlarm.Alarm+=new AlarmEventHandler(callPolice);
      // or
      myAlarm.Alarm-=new AlarmEventHandler(callPolice);
      

      但从类内部来看,Alarm 只是 AlarmEventHandler 类型的委托,因此您可以按照代码显示的方式进行操作:

              AlarmEventHandler handler = Alarm;
              if (handler != null)
              {
                  // Invokes the delegates.
                  handler(this, e);
              }
      

      【讨论】:

        【解决方案5】:

        将基类作为(非引用)参数的函数可以转换为将派生类作为参数的委托。这是因为无论何时使用采用派生类的函数,都可以安全地替换采用基类的函数。

        void TakesObject(object o)
        {
        ...
        }
        
        Action<string> myAction=TakesObject;
        

        您只能通过传入字符串来调用 myAction。并且由于每个字符串都是一个对象,因此 TakesObject 的合同得以履行。

        在你的情况下是有效的,因为每个AlarmEventArgs 也是一个EventArgs。因此,您的事件处理程序的合同要求不如事件使用的委托类型的合同保证严格。

        这称为协方差和反方差。返回类型有协方差,参数有反方差。

        在 MSDN 上查看这篇文章:
        Using Variance in Delegates (C# and Visual Basic)

        【讨论】:

          猜你喜欢
          • 2010-11-01
          • 2016-11-10
          • 1970-01-01
          • 2022-01-19
          • 1970-01-01
          • 2010-10-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多