在Generics FAQ: Best Practices中说:
编译器将允许您将泛型类型参数显式地转换为任何接口,但不能转发给类:
interface ISomeInterface
{...}
class SomeClass
{...}
class MyClass<T>
{
void SomeMethod(T t)
{
ISomeInterface obj1 = (ISomeInterface)t;//Compiles
SomeClass obj2 = (SomeClass)t; //Does not compile
}
}
除非未将类/接口指定为约束类型,否则我认为类和接口的限制都是合理的。
那么为什么这样的行为,为什么允许接口呢?
答案 0 :(得分:50)
我认为这是因为转化为SomeClass
可能意味着任何数量的事情取决于可用的转化次数,而转化为ISomeInterface
只能是参考转化或拳击转化。< / p>
选项:
首先投射到对象:
SomeClass obj2 = (SomeClass) (object) t;
改为使用as
:
SomeClass obj2 = t as SomeClass;
显然,在第二种情况下,如果t
不 a SomeClass
,您还需要执行无效检查。
编辑:对此的推理在C#4规范的第6.2.7节中给出:
上述规则不允许从无约束类型参数直接显式转换为非接口类型,这可能会令人惊讶。此规则的原因是为了防止混淆并使这种转换的语义清晰。例如,请考虑以下声明:
class X<T> { public static long F(T t) { return (long)t; // Error } }
如果允许将t直接显式转换为int,则可能很容易预期
X<int>.F(7)
将返回7L。但是,它不会,因为仅在绑定时已知类型为数字时才考虑标准数字转换。为了使语义清晰,必须编写上面的例子:class X<T> { public static long F(T t) { return (long)(object)t; // Ok, but will only work when T is long } }
此代码现在将编译,但执行
X<int>.F(7)
会在运行时抛出异常,因为盒装的int无法直接转换为long。
答案 1 :(得分:2)
在C#的继承原则中,接口可以多次继承,但只能一次继承。 由于接口的继承具有复杂的层次结构, .net框架不需要在编译时确保泛型类型T是特定接口。(编辑) 相反,可以通过在编译时声明类型约束来确保类是一个特定的类,如下面的代码。
class MyClass<T> where T : SomeClass
{
void SomeMethod(T t)
{
ISomeInterface obj1 = (ISomeInterface)t;
SomeClass obj2 = (SomeClass)t;
}
}