[英]Delegate doesn't accept subclass?
我的代表似乎不接受一個子類,我認為一個例子是最簡單的。
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()");
}
}
當我將Test更改為接受B
它會拋出編譯錯誤。 這不奇怪,因為B
延伸A
?
編譯錯誤 :
測試沒有重載匹配回調
有沒有辦法讓我的委托接受一個擴展A
的類?
這不奇怪,因為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());
這顯然是合法的。 dm需要是一個采用哺乳動物的方法,它是。
D dt = DoTiger;
dt(new Giraffe());
這顯然是非法的。 你不能指定一種方法將老虎帶給一個哺乳動物的代表,因為一個哺乳動物的代表可以接受任何哺乳動物,而不僅僅是老虎。 如果這是合法的,那么就可以將長頸鹿傳遞給一只需虎的方法。
那這個呢?
D da = DoAnimal;
da(new Giraffe());
沒關系。 da是一種接受任何哺乳動物的方法的代表。 一種明確攝取任何動物的方法也需要任何哺乳動物。 您可以將DoAnimal(動物)分配給委托D(哺乳動物),因為Mammal擴展了Animal。 你現在看到你如何向后延伸方向?
另一方面, 返回類型以您認為的方式工作:
delegate Mammal F();
static Animal GetAnimal() {...}
static Mammal GetMammal() {...}
static Tiger GetTiger() {...}
F fm = GetMammal;
Mammal m = fm();
沒問題。
F ft = GetTiger;
Mammal t = ft();
沒問題; GetTiger返回一個Tiger,因此您可以將其分配給需要其目標返回哺乳動物的委托。
F fa = GetAnimal;
Mammal a = fa();
那不好。 GetAnimal可能會返回一個Snake,現在你有一個變量類型為Mammal,其中包含一個Snake。 這必須是非法的。
此功能稱為“成員組轉換的協方差和逆變”,它在C#2.0中引入。 有關此主題的更多信息,請參閱我的文章:
這並不奇怪,因為如果你有一個擴展A
C
類對象,如果它只接受一個B
則傳遞給Test()
是沒有意義的。 用於Callback
任何方法都必須接受任何 A
,而不僅僅是特定的子類。 您需要更改Callback
委托簽名接受B
,如果你想Test()
接受B
為好。
class C : A {};
Callback callback = Test;
callback(new C()); //what if Test() accepted B???
這很容易理解。 現在我們有:
class A { }
class B : A { }
場景1開頭
public delegate void CallBack(A a);
public void Test(A a) { }
CallBack cb = new CallBack(Test);
cb(new A()); //good and easy usage
場景2 CallBack(A a)
和Test(B b)
//compile error, because Test(B b) has a smaller argument scope than CallBack
//CallBack cb = new CallBack(Test);
場景3回 CallBack(B b)
和Test(A a)
CallBack cb = new CallBack(Test);
cb(new A()); //no error, becasue B can convert to A
C#代表支持協方差和逆變 ,所以這應該工作。
問題是過載。
// this delegate supports contravariance - and subclass of A should work
delegate void CallBack(A a);
// however this can't pick up either Test because both could be used
static CallBack callBack = new CallBack(Test);
必須在編譯時解析哪個重載方法簽名( Test(A a)
或Test(B b)
) - 但兩者都可以應用,因此會引發錯誤。
您可以通過拆分重載來避免這種情況:
static void TestA(A a)
{
Console.WriteLine("Test(a)");
}
// Compilation error occurs if Test becomes:
static void TestB(B a)
{
Console.WriteLine("Test(b)");
}
// this is valid because it's an exact match
static CallBack callBackA = new CallBack(TestA);
// this is valid because delegates support contravariance
static CallBack callBackB = new CallBack(TestB);
無論哪種情況,你都可以通過B
:
// B is subclass of A, so can be passed to TestA
callBackA(new B());
// CallBack supports contravariance, so can call TestB
callBackB(new B());
鑒於你有這種逆轉,你為什么需要重載?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.