考虑这段代码,
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()
实际上会调用类SomeMethod()
的{{1}}。所以在这一点上,我几乎没有问题:
A
的哪个实例,A
被调用? SomeMethod
如何知道要调用委托的实例? CLR如何在这里工作?B
是私有方法,那么SomeMethod
如何从类B
外部调用此方法?编辑:
在阅读了前几个答案后,我发现A
有一个Delegate
属性,在该属性上调用了委托。但我真的不明白这个Target
属性的确切步骤是什么?是谁设定的?当我写Target
时,它是否也设置了b.SomeEvent += this.SomeMethod;
属性?究竟是怎么回事?
答案 0 :(得分:3)
b.SomeEvent += this.SomeMethod
这里有很多糖会阻止你看到真正发生的事情。写出来,它类似于:
b.SomeEvent.add(new MulticastDelegate(this, SomeMethod)); // not legal code
其中add()是事件的add访问器,编译器会在您未明确声明自己生成器时自动生成一个。委托构造函数的第一个参数是您要询问的对象实例,即委托对象的Target属性。请注意,这会产生副作用,事件订阅会保留对b
对象的引用。这可以防止它被垃圾收集,这在调用事件时会相当糟糕。
那也可能是个问题,你可能会无意中泄漏对象引用。你的代码没有好的办法来取消订阅事件处理程序,所以只要你调用h()的B对象,A对象就会生存。
答案 1 :(得分:2)
委托包含调用方法的目标引用。您可以使用Delegate.Target
属性进行检查。在这种情况下,将在调用f
的实例上调用它。 (如果您正在调用静态方法,则为null。)
至于隐私 - 这只是代表们的一个特点。您只能在有权访问私有方法的代码中创建代理,但您可以在任何地方运行。可以认为这就像通过从公共接口实现中调用私有方法来实现接口一样。
答案 2 :(得分:2)
在A的哪个实例上调用SomeMethod? B如何知道要调用委托的实例? CLR如何在这里工作?
委托实际上包含对实际实例的引用。这将导致它在调用它的特定实例上调用。
另外,SomeMethod是一个私有方法,那么为什么B能够从A类外部调用这个方法呢?
它不直接执行该方法 - 它执行委托。这里有一点不同 - 私有约束只适用于该方法,但由于类本身创建了委托,因此它可以访问该方法,因此一切正常。
答案 3 :(得分:1)
A
在类之外传递了委托表示。特定Delegate
实例具有Target
属性;这表示调用委托时将使用的实例。