我遇到类似于以下代码的运行时转换错误。首先,我有一个设置了访客模式的界面:
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> { }
此代码编译完全正常,但在运行时(从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
。
答案 0 :(得分:0)
这最终成为一个与我认为与之相关的一切完全无关的问题。缺点是代表未能正确地转换值,而不是通用输入。