Delegate不接受子类?

Kev*_*vin 5 c# inheritance delegates

我的代表似乎不接受一个子类,我认为一个例子是最简单的.

public class A
{
     public A() { }
}

public class B : A
{
     public B() { }
}

public class Program
{
     private delegate void CallBack(A a);
     private static CallBack callBack = new CallBack(Test);

     public Main(string[] args)
     {
          callBack(new B());
     }

     private static void Test(A a)
     {
          Console.WriteLine("Test()");    
     }

     // Compilation error occurs if Test becomes:
     private static void Test(B a)
     {
          Console.WriteLine("Test()");
     }
 }
Run Code Online (Sandbox Code Playgroud)

当我更改Test以接受B它时会抛出编译错误.是不是因为B延伸A

编译错误:

测试没有重载匹配回调

有没有办法让我的委托接受一个扩展的类A

Eri*_*ert 9

这不奇怪,因为B延伸A?

你有正确的想法,但方向错误.让我们考虑一个更容易推理的例子:

class Animal {}
class Reptile : Animal {}
class Snake : Reptile {}
class Mammal : Animal {}
class Tiger : Mammal {}
class Giraffe : Mammal {}
delegate void D(Mammal m);
static void DoAnimal(Animal a) {}
static void DoMammal(Mammal m) {}
static void DoTiger(Tiger t) {}

D dm = DoMammal;
dm(new Tiger());
Run Code Online (Sandbox Code Playgroud)

这显然是合法的.dm需要是一个采用哺乳动物的方法,而且它是.

D dt = DoTiger;
dt(new Giraffe());
Run Code Online (Sandbox Code Playgroud)

这显然是非法的.你不能指定一种方法将老虎带给一个哺乳动物的代表,因为一个哺乳动物的代表可以接受任何哺乳动物,而不仅仅是老虎.如果这是合法的,那么就可以将长颈鹿传递给一只需虎的方法.

那这个呢?

D da = DoAnimal;
da(new Giraffe());
Run Code Online (Sandbox Code Playgroud)

没关系.da是一种接受任何哺乳动物的方法的代表.一种明确摄取任何动物的方法也需要任何哺乳动物.您可以将DoAnimal(动物)分配给委托D(哺乳动物),因为Mammal扩展了Animal.你现在看到你如何向后延伸方向?

另一方面,返回类型以您认为的方式工作:

delegate Mammal F();
static Animal GetAnimal() {...}
static Mammal GetMammal() {...}
static Tiger GetTiger() {...}

F fm = GetMammal; 
Mammal m = fm();
Run Code Online (Sandbox Code Playgroud)

没问题.

F ft = GetTiger;
Mammal t = ft();
Run Code Online (Sandbox Code Playgroud)

没问题; GetTiger返回一个Tiger,因此您可以将其分配给需要其目标返回哺乳动物的委托.

F fa = GetAnimal;
Mammal a = fa();
Run Code Online (Sandbox Code Playgroud)

那不好.GetAnimal可能会返回一个Snake,现在你有一个变量类型为Mammal,其中包含一个Snake.这必须是非法的.

此功能称为"成员组转换的协方差和逆变",它在C#2.0中引入.有关此主题的更多信息,请参阅我的文章:

http://blogs.msdn.com/b/ericlippert/archive/2007/10/19/covariance-and-contravariance-in-c-part-three-member-group-conversion-variance.aspx


Mar*_*ade 3

这并不奇怪,因为如果您有一个Cextends类的对象ATest()那么如果它只接受B. 用于 a 的任何方法都Callback必须接受任何 A,而不仅仅是特定的子类。如果您也想接受,则需要将Callback委托签名更改为接受。BTest()B

class C : A {};

Callback callback = Test;

callback(new C()); //what if Test() accepted B???
Run Code Online (Sandbox Code Playgroud)

  • @Kevin:那你认为这怎么可能呢?当您的方法需要“LoveLetterEvent”时,如果有人将“NutellaEvent”传递给您的回调,您预计会发生什么? (2认同)