我不明白纯委托和事件字段之间的区别

时间:2012-05-22 16:57:05

标签: c# events delegates

代表:我明白了。但是当我搬到活动时,很多事情我都不太了解。我在网上读过书,MSDN和一些简单的例子,它们都有相同的结构。例如,以下是链接:Event Example

我采用第一个例子,作者说这是关于C#事件最简单的例子。

这是他的代码:

public class Metronome
{
    public event TickHandler Tick;
    public EventArgs e = null;
    public delegate void TickHandler(Metronome m, EventArgs e);
    public void Start()
    {
        while (true)
        {
            System.Threading.Thread.Sleep(3000);
            if (Tick != null)
            {
                Tick(this, e);
            }
        }
    }
}

public class Listener
{
    public void Subscribe(Metronome m)
    {
        m.Tick += new Metronome.TickHandler(HeardIt);
    }
    private void HeardIt(Metronome m, EventArgs e)
    {
        System.Console.WriteLine("HEARD IT");
    }
}

class Test
{
    static void Main()
    {
        Metronome m = new Metronome();
        Listener l = new Listener();
        l.Subscribe(m);
        m.Start();
    }
}

您可以注意到行:public event TickHandler Tick。当我更改为public TickHandler Tick时,程序仍然运行相同。但我理解新线,因为它只是一个纯粹的代表。

所以,我的问题是:event关键字的真正目的是什么:public event TickHandler Tick。这非常重要,因为所有示例总是这样使用,但我无法解释原因。

谢谢:)

7 个答案:

答案 0 :(得分:9)

代理和事件是相关的概念,但它们不是相同的东西。 “代表”一词往往有两个含义(经常被掩盖):

  • 委托类型,类似于单个方法接口。 (存在显着差异,但这是一个合理的起点。)
  • 该类型的实例,通常通过方法组创建,这样当“调用”委托时,将调用该方法。

事件既不是那些事件。它是一种类型的成员 - 一对添加/删除方法,让代理人订阅或取消订阅该事件。使用foo.SomeEvent += handler;foo.SomeEvent -= handler;时会使用添加和删除方法。

这非常类似于属性实际上是一对get / set方法(或者可能只是两者中的一个)。

当您声明类似字段的事件时:

public event TickHandler Tick;

编译器会向您的类添加成员有点,如下所示:

private TickHandler tick;

public event TickHandler
{
    add { tick += value; }
    remove { tick -= value; }
}

这比这复杂一点,但这是基本的想法 - 它是一个简单的事件实现,就像一个自动实现的属性。从课堂内部开始,您可以访问课程领域,而在课堂之外,您最终只会使用该课程。

我个人认为遗憾的是,类似字段的事件的声明看起来像就像一个委托类型的字段 - 它会导致一些错误的(IMO)语句答案,好像event关键字“修改”一个字段声明 - 实际上它意味着你宣布一些完全不同的东西。我认为,如果类似字段的事件看起来更像自动实现的属性,例如

,那就更清楚了
// Not real C#, but I wish it were...
public event TickHandler Tick { add; remove; }

我有一个whole article进入更详细的细节,你会发现它很有用。

答案 1 :(得分:7)

event关键字基本上限制了delegate上的操作。 您无法再使用=运算符手动分配它。

您只能逐个添加(使用+=)或删除(使用-=)代表。这样做是为了防止某些订阅者“覆盖”其他订阅。

因此,你无法做到:m.Tick = new Metronome.TickHandler(HeardIt)

答案 2 :(得分:3)

event”是一个修饰语。有什么好处?

  1. 您可以在界面中使用事件
  2. 只有声明它的类才能调用事件
  3. 事件会公开addremove访问者,您可以覆盖并执行自定义内容
  4. 事件将您限制为已分配方法SomeMethod(object source, EventArgs args)的特定签名,该签名为您提供有关该活动的其他信息。

答案 3 :(得分:1)

你是对的 - 添加event关键字似乎几乎是多余的。但是,作为事件的字段和键入纯委托的字段之间存在关键区别。使用event关键字意味着包含对象外部的对象可以订阅委托,但是它们不能调用它。删除event关键字时,外部对象可以订阅并调用委托(可见性允许。)

答案 4 :(得分:1)

向程序添加侦听器时,添加事件,而不是委托

看你的代码m.Tick + =

你看到那个部分就在那里你要求属性(类型事件)并且你正在向它添加一个带有+ =的监听器。现在,您只能向Tick属性添加TickHandler类型,如果您覆盖它,则必须使用与TickHandler相同的格式。

非常类似于添加到字符串或int。

string stringTest = string.Empty;
stringTest += "this works";
stringTest += 4; //this doesn't though
int intTest = 0;
intTest += 1; //works because the type is the same
intTest += "This doesn't work";
Metronome m = new Metronome();
Metronome.TickHandler myTicker = new Metronome.TickHandler(function);
m.Tick += myTicker; //works because it is the right type
m.Tick += 4; //doesn't work... wrong type
m.Tick += "This doesnt work either"; //string type is not TickHandler type

是否清除了一些?

答案 5 :(得分:1)

据我所知,一个事件基本上是一个多播委托,但是对于基本操作有不同的访问规则,可以对它们所定义的类内外的委托和事件执行。

操作是:

使用=运算符

进行分配

使用+ =和 - =运算符

添加/删除

使用()运算符

调用
              Operation         | delegate   | event
              ------------------+------------+--------
Inside class  += / -=           | valid      | valid
              ------------------+------------+--------
Inside class  =                 | valid      | valid
              ------------------+------------+--------
Inside class  ()                | valid      | valid
              ------------------+------------+--------
Outside class  += / -=          | valid      | valid
              ------------------+------------+--------
Outside class  =                | valid      | not valid
              ------------------+------------+--------
Outside class  ()               | valid      | not valid

这给你封装,这总是很好的OOP风格。 : - )

答案 6 :(得分:0)

我认为使用委托和事件之间的主要区别在于事件只能由服务器引发(意味着类的作者)

如果您现在删除了event关键字,则可以在m.Tick(sender,e)中提升Listener,否则不会。

public class Listener
{
  public void Subscribe(Metronome m)
  {
    m.Tick += new Metronome.TickHandler(HeardIt);
  }

  private void RaisTick(object sender, EventArgs e)
  {
      m.Tick(sender,e);
  }
  private void HeardIt(Metronome m, EventArgs e)
  {
     System.Console.WriteLine("HEARD IT");
  }

}

相关问题