namespace TestCast { public class Fruit { } public class Apple : Fruit { } public static class Test { public static void TestFruit<FruitType>(FruitType fruit) where FruitType : Fruit { if (fruit is Apple) { Apple apple = (Apple)fruit; } } } }
对Apple的转换失败,并显示错误:“无法将”FruitType“类型转换为”TestCast.Apple“.但是,如果我更改行使用as操作符,它编译没有错误:
Apple apple = fruit as Apple;
有人可以解释为什么会这样吗?
解决方法
Could someone please explain why this is the case?
“为什么”问题难以回答?答案是“因为这是规范说的”,那么自然的问题就是“为什么说规范呢?
所以让我让问题更加清晰:
What language design factors influenced the decision to make the given cast operator illegal on constrained type parameters?
请考虑以下情况.你有一个基本类型的水果,派生类型苹果和香蕉,现在是重要的一部分,从苹果到香蕉的用户定义的转换.
被称为M< Apple>?你认为这应该做什么?
void M<T>(T t) where T : Fruit { Banana b = (Banana)t; }
大多数阅读代码的人都会说,这应该称为从苹果到香蕉的用户定义的转换.但C#泛型不是C模板;该方法对于每个通用构造都不会从头重新编译.相反,该方法被编译一次,并且在该编译期间,为每个可能的通用实例化确定每个运算符(包括转换)的含义.
M< Apple>的身体将必须有一个用户定义的转换. M香蕉的身体将有一个身份转换. M<樱桃>会是一个错误.我们在通用方法中不能具有运算符的三个不同含义,因此运算符被拒绝.
相反,你要做的是:
void M<T>(T t) where T : Fruit { Banana b = (Banana)(object)t; }
现在这两个转换都很清楚.转换为对象是一个隐式引用转换;转换为香蕉是一个明确的参考转换.用户定义的转换从不被调用,如果这是用Cherry构建的,则错误在运行时,而不是编译时,因为它始终是从对象转换.
作为运算符不像演员运算符;它总是意味着同样的事情,无论它给出什么类型,因为as操作符从不调用用户定义的转换.因此,它可以用于一个演员是非法的上下文.