我遇到了類似於以下代碼的運行時轉換錯誤。首先,我有一個訪問者模式的接口設置: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
。
你完全可以減少到最小的例子嗎?我不會認爲我們需要所有的代碼才能顯示問題。 –
雖然你聲稱它是一個*例外*並不能很好地適應編譯器錯誤「錯誤CS1503」...... –
我發現了一些更多的信息,表明其餘的代碼是一個紅鯡魚。我想盡可能地完整,因爲這對我來說毫無意義。 –