c# - 无法转换类型 : why is it necesssary to cast twice?

标签 c# generics inheritance

鉴于这个高度简化的例子:

abstract class Animal { }

class Dog : Animal
{
  public void Bark() { }
}
class Cat : Animal
{
  public void Mew() { }
}

class SoundRecorder<T> where T : Animal
{
  private readonly T _animal;

  public SoundRecorder(T animal) { _animal = animal; }

  public void RecordSound(string fact)
  {
    if (this._animal is Dog)
    {
      ((Dog)this._animal).Bark(); // Compiler: Cannot convert type 'T' to 'Dog'.
      ((Dog)(Animal)this._animal).Bark(); // Compiles OK
    }
  }
}

为什么编译器会提示单一类型转换 (Dog)this._animal ?我只是不明白为什么编译器似乎需要通过执行两次强制转换来获得帮助。 _animal只能是 Animal , 它可以?

当然,这个问题是由一个现实生活中的例子激发的,在这个例子中,我必须以一种类似的转换是最方便的方式来修改现有代码,而不用重构整个代码。 (是的,使用组合而不是继承;))。

最佳答案

问题是编译器不能保证 _animal 可以转换为 Dog,因为您给 SoundRecorded 类型参数的唯一限制是类型应该是 Animal 或从 Animal 继承。所以编译器实际上在想:如果你构造一个 SoundRecorder<Cat> 会怎样? ,则转换操作无效。

不幸的是(或不是),编译器不够聪明,无法通过提前执行“is”检查来安全地保护代码免于到达那里。

如果您要将给定的动物存储为实际动物,这不会成为问题,因为编译器始终允许从基本类型到派生类型的任何强制转换。尽管编译器不允许从 Dog 转换为 Cat

编辑 有关更具体的解释,请参阅 Jon Skeets 的回答。

关于c# - 无法转换类型 : why is it necesssary to cast twice?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7978316/

相关文章:

java - Number 操作的通用类

c++ - 通过继承实现接口(interface)

c# - 静态方法继承的正确替代方法是什么?

c# - 在应用程序栏项目中添加/删除事件订阅者?

c# - NLog 和 SQLite 错误

c# - string.ToLower 和 TextInfo.ToLower 之间的区别

c# - 通用存储库模式和理解语法

泛型的 Java 简称

CSS - 容器高度与父 div 高度相同,除非父 div 小于容器 div

c# - Where() 在抽象层返回新的 self