[英]Why can delegates can be used interchangeably for Class methods and Static functions?
我使用委托很多年了,并没有真正考虑过它们。 但是我最近因为假设委托在引用类方法时存储了this
引用而大吃一惊。 下面的例子说明了我理解上的差距。
public class SomeClass
{
public SomeClass(int someProperty)
{
SomeProperty = someProperty;
}
public int SomeProperty
{
get;
set;
}
// Throw in a Member field into the mix
public int ClassAdd(int x, int y)
{
return x + y + SomeProperty;
}
}
public static class SomeStaticClass
{
public static int StaticAdd(int x, int y)
{
return x + y;
}
}
为什么我可以同时添加静态和实例订阅者?
class TestClass
{
delegate int myAddDelegate(int x, int y);
private void UseDelegates()
{
myAddDelegate algorithm;
algorithm = new SomeClass(3).ClassAdd;
// Surprised that I could add static methods to my delegate?
algorithm += SomeStaticClass.StaticAdd;
// I'm fine with just one of the results being returned.
int answer = algorithm(5, 10);
}
}
到底发生了什么? ;)
如果您创建引用实例方法的委托,它将在支持委托的Target
属性的字段中捕获this
(或相关引用)。 如果您创建引用静态方法的委托,则Target
将为 null。 从逻辑上讲,如果您使用的是静态方法,则不需要实例。
作为一个额外的复杂性,您可以捕获扩展方法,就好像它们是扩展类型的实例方法一样:
static class Extensions
{
public static void Foo(this string x)
{
Console.WriteLine("Calling Foo on " + x);
}
}
class Test
{
static void Main()
{
Action action = "text".Foo;
Console.WriteLine(action.Target); // Prints "text"
}
}
至于为什么你可以做到这一切:因为它很有用,没有理由不让你这样做:)
C#中没有静态函数,它们实际上是静态方法(所以有静态方法和实例方法)。 每个委托基本上都是指向方法this
指针和方法将在其上执行的指针,它是委托的Target属性。 在静态方法的情况下,它将为空。 由于委托携带对对象的引用,如果您忘记取消订阅,它可能会导致内存泄漏。
委托的美妙之处在于它们对静态和实例方法都有效。 如果将静态方法分配给委托,静态方法将按原样使用,因为它不需要任何非静态上下文即可工作。 对于实例方法,对实例的引用与方法指针一起存储,以便在调用方法时可以使用必要的上下文( this
引用)。 这意味着当您将实例方法分配给委托时,您还必须提供一个实例 - 通过显式指定它,或者通过从实例上下文内部分配给委托。
大多数时候,这“行之有效”,您无需考虑任何事情。 但有一个警告:如果将实例方法分配给委托,则会创建对该实例的另一个引用,并且只要该方法仍然分配给委托(或订阅事件),也会有一个对实例的引用实例,因此 GC 永远不会收集它。 这就是为什么您在清理自己时应该始终取消订阅所有事件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.