2017-04-25 317 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

这最终成为一个与我认为与之相关的事情完全无关的问题。它的缺点是代表没有正确地投入价值,而不是通用投入。