2011-03-25 140 views
5

考虑以下代码,什么类的委托被调用?

public class A 
{ 
    //... 
    void f() 
    { 
      B b = new B(); 
      b.SomeEvent += this.SomeMethod; 
    } 
    void SomeMethod() {} 
} 

public class B 
{ 
    //... 

    public event SomeEventHandler SomeEvent; 

    void h() 
    { 
      if (SomeEvent != null) 
      { 
       SomeEvent.invoke(); 
      } 
    } 
} 

在此代码段,SomeEvent.invoke()实际上调用ASomeMethod()。所以在这一点上,我有几个问题:

  • 什么样的ASomeMethod被调用? B如何知道要调用委托的实例? CLR如何在这里工作?
  • 另外,SomeMethod是一个私人方法,那么B怎么能够从类A以外调用此方法?

编辑:

阅读前几个答案后,我才知道,Delegate有其代表被调用的Target属性。但我无法真正理解这个Target属性设置的步骤?谁设定的?当我写b.SomeEvent += this.SomeMethod;时,它是否也设置了Target属性?究竟如何?

回答

2
b.SomeEvent += this.SomeMethod 

这里有很多糖,可以防止看到真正发生的情况。写出来,它类似于此:

b.SomeEvent.add(new MulticastDelegate(this, SomeMethod));  // not legal code 

其中添加()是事件的add访问,编译器会自动生成一个,当你不声明自己明确。委托构造函数的第一个参数是您询问的对象实例,委托对象的Target属性。请注意,这具有副作用,事件订阅会保留对您的b对象的引用。这可以防止它被垃圾收集,这在事件被调用时会相当糟糕。

这也可能是一个问题,可以无意中泄漏对象的引用。在您的代码中没有好的方法来取消订阅事件处理程序,因此A对象将与您在其中调用h()的B对象一样长。

+0

最后一篇文章...这告诉我我正在寻找的东西。 +1 – Nawaz 2011-03-25 19:47:20

1
  • 无论实例被附接至所述事件
  • 当由于A通过委托表示给它的类以外使用。

一个特定的Delegate实例有一个Target属性;这表示调用委托时将使用的实例。

2

委托包含调用该方法的目标引用。您可以使用Delegate.Target属性来检查它。在这种情况下,它将在调用f的实例上调用。 (如果你正在调用静态方法,则为空。)

至于隐私 - 这只是代表的特征之一。你只能在里面创建这个委托代码里面有一个私有方法,但是你可以在里运行它在任何地方。认为这就像通过从公共接口实现中调用私有方法来实现接口一样。

+0

乔恩:我编辑了我的问题。请参阅编辑。我想深入了解它。 – Nawaz 2011-03-25 18:52:22

+0

顺便说一句,我已经买了你的书,可能你记得我曾经告诉过你,当我命令它。所以,如果你在书中讨论过这个问题,请告诉我这一章节,以便我自己仔细阅读。 – Nawaz 2011-03-25 18:54:05

+0

@Nawaz:第2章包含了很多与会代表,是的。享受:) – 2011-03-25 19:00:49

2

A,SomeMethod被调用的是什么实例? B如何知道要调用委托的实例? CLR如何在这里工作?

委托实际上包含对实际实例的引用。这将导致它调用它被调用的特定实例。

此外,SomeMethod是一个私有方法,那么B怎么能够从类A外部调用这个方法呢?

它不直接执行该方法 - 它执行委托代理。这里有一个区别 - 私有约束只适用于该方法,但由于类本身创建委托,它有权访问该方法,所以一切正常。

相关问题