![](/img/trans.png)
[英]Passing delegate declaration to a class and then later changing its value to be invoked
[英]On what instance of class delegate gets invoked?
考虑一下这段代码
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()
实际上调用了A
类的SomeMethod()
。 所以在这一点上,我几乎没有问题:
A
, SomeMethod
被调用? B
如何知道要调用委托的实例? CLR如何在这里工作? SomeMethod
是一个私有方法,那么为什么B
能够从A
类外部调用这个方法呢? 编辑:
在阅读了前几个答案之后,我开始知道Delegate
有一个Target
属性,在该属性上调用了委托。 但我真的不明白这个Target
属性到底是什么步骤? 是谁设定的? 当我写b.SomeEvent += this.SomeMethod;
,它是否也设置了Target
属性? 究竟怎么样?
b.SomeEvent += this.SomeMethod
这里有很多糖会阻止你看到真正发生的事情。 写出来,它类似于:
b.SomeEvent.add(new MulticastDelegate(this, SomeMethod)); // not legal code
其中add()是事件的add访问器,当您没有显式声明自己的访问器时,编译器会自动生成一个。 委托构造函数的第一个参数是您要询问的对象实例,即委托对象的Target属性。 请注意,这会产生副作用,事件订阅会保留对b
对象的引用。 这可以防止它被垃圾收集,这在调用事件时会相当糟糕。
这也可能是一个问题,你可以无意中泄漏对象引用。 在代码中没有好的方法来取消订阅事件处理程序,因此只要你调用h()的B对象,A对象就会生存。
委托包含调用方法的目标引用。 您可以使用Delegate.Target
属性进行检查。 在这种情况下,它将在调用f
的实例上调用。 (如果您正在调用静态方法,则为null。)
至于隐私 - 这只是代表的一个特点。 您只能在有权访问私有方法的代码中创建委托,但您可以在任何地方运行它。 可以认为这就像通过从公共接口实现调用私有方法来实现接口一样。
在什么实例的A,SomeMethod被调用? B如何知道要调用委托的实例? CLR如何在这里工作?
委托实际上包含对实际实例的引用。 这将导致它在调用它的特定实例上调用。
另外,SomeMethod是一个私有方法,那么为什么B能够从A类外部调用这个方法呢?
它不直接执行方法 - 它执行委托 。 这里有一点不同 - 私有约束仅适用于该方法,但由于类本身创建了委托,因此它可以访问该方法,因此一切正常。
A
在类之外传递了委托表示。 特定的Delegate
实例具有Target
属性; 这表示调用委托时将使用的实例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.