2017-04-25 242 views
-3

我遇到了類似於以下代碼的運行時轉換錯誤。首先,我有一個訪問者模式的接口設置:C#運行時將約束泛型類型轉換爲約束類型

public interface IAnimalVisitor<out T> 
{ 
    T Visit(Dog a); 
    T Visit(Cat a); 
} 

public interface IAnimal 
{ 
    string Name { get; } 

    T Accept<T>(IAnimalVisitor<T> v); 
} 

public abstract class AnimalBase : IAnimal 
{ 
    public string Name { get; } 

    protected AnimalBase(string name) 
    { 
     Name = name; 
    } 

    public abstract T Accept<T>(IAnimalVisitor<T> v); 
} 

public class Dog : AnimalBase 
{ 
    public Dog(string name) : base(name) { } 

    public override T Accept<T>(IAnimalVisitor<T> v) 
    { 
     return v.Visit(this); 
    } 
} 

public class Cat : AnimalBase 
{ 
    public Cat(string name) : base(name) { } 

    public override T Accept<T>(IAnimalVisitor<T> v) 
    { 
     return v.Visit(this); 
    } 
} 

然後一個類實現訪問者模式(隱藏的嵌套類):

public class AnimalSpeaker 
{ 
    private class SpeakerVisitor : IAnimalVisitor<string> 
    { 
     public string Visit(Dog a) 
     { 
      return "Woof"; 
     } 

     public string Visit(Cat a) 
     { 
      return "Meow"; 
     } 
    } 

    private readonly SpeakerVisitor _SpeakerVisitor = new SpeakerVisitor(); 

    public string Speak(IAnimal a) 
    { 
     return a.Accept(_SpeakerVisitor); 
    } 
} 

最後我有一個泛型類受限於消耗類型IAnimals,它通過它的包封類傳遞一個實例給訪問者的:

public abstract class AnimalSignTextBuilderBase<TAnimal> 
    where TAnimal : IAnimal 
{ 
    private readonly AnimalSpeaker _AnimalSpeaker = new AnimalSpeaker(); 

    public string BuildSignText(TAnimal a) 
    { 
     var spokenText = _AnimalSpeaker.Speak(a); 
     return $"{a.Name} says {spokenText}."; 
    } 
} 

public class DogSignTextBuilder : AnimalSignTextBuilderBase<Dog> { } 
public class CatSignTextBuilder : AnimalSignTextBuilderBase<Cat> { } 

此代碼編譯完全正常,但在運行時(它是從一個被稱爲n ASP.net請求)當我打電話

new DogSignTextBuilder().BuildSignText(new Dog("Fido")) 

我得到一個無效的轉換異常。這是由致電_AnimalSpeaker.Speak(a)造成的。

我不知道爲什麼會拋出。更重要的是,我可以在Visual Studio中調試代碼,並在即時窗口中輸入a is IAnimal,從而產生true。我還可以在即時窗口中輸入_AnimalSpeaker.Speak(a)和它導致以下錯誤:

error CS1503: Argument 1: cannot convert from 'TAnimal' to 'IAnimal' 

我還可以利用這個例子和dotnetfiddle張貼,並把它做工精細,所以在這一點上,我在關於發生了什麼事情的想法完全喪失。

編輯:我還發現,由於剛剛在即時窗口調用a.Name失敗:

error CS1061: 'TAnimal' does not contain a definition for 'Name' and no extension method 'Name' accepting a first argument of type 'TAnimal' could be found (are you missing a using directive or an assembly reference?) 

我檢查了我的引用和他們都在那裏。到目前爲止,似乎通用約束在運行時被忽略。我也可以輸入(a as IAnimal).Name,正確返回Fido

+2

你完全可以減少到最小的例子嗎?我不會認爲我們需要所有的代碼才能顯示問題。 –

+1

雖然你聲稱它是一個*例外*並不能很好地適應編譯器錯誤「錯誤CS1503」...... –

+0

我發現了一些更多的信息,表明其餘的代碼是一個紅鯡魚。我想盡可能地完整,因爲這對我來說毫無意義。 –

回答

0

這最終成爲一個與我認爲與之相關的事情完全無關的問題。它的缺點是代表沒有正確地投入價值,而不是通用投入。