【发布时间】:2012-05-25 23:32:23
【问题描述】:
我昨天偶然发现了这个奇怪的情况,t as D 返回一个非空值,但(D)t 导致编译器错误。
因为我很着急,所以我只使用了t as D 并继续,但我很好奇为什么演员表无效,因为t 真的是D。谁能解释一下为什么编译器不喜欢演员表?
class Program
{
public class B<T> where T : B<T> { }
public class D : B<D> { public void M() { Console.Out.WriteLine("D.M called."); } }
static void Main() { M(new D()); }
public static void M<T>(T t) where T : B<T>
{
// Works as expected: prints "D.M called."
var d = t as D;
if (d != null)
d.M();
// Compiler error: "Cannot cast expression of type 'T' to type 'D'."
// even though t really is a D!
if (t is D)
((D)t).M();
}
}
编辑: 玩玩,我认为这是一个更清晰的例子。在这两种情况下,t 都被限制为B,并且可能是D。但是泛型的情况不会编译。在确定强制转换是否合法时,C# 是否只是忽略了通用约束?即使它确实忽略了它,t 仍然可能是D;那么为什么这是编译时错误而不是运行时异常呢?
class Program2
{
public class B { }
public class D : B { public void M() { } }
static void Main()
{
M(new D());
}
public static void M(B t)
{
// Works fine!
if (t is D)
((D)t).M();
}
public static void M<T>(T t) where T : B
{
// Compile error!
if (t is D)
((D)t).M();
}
}
【问题讨论】:
-
赌
(D)(object)t作品 -
从this link 的评论中,我找到了指向your answer 的链接。本质上,有些变量类型不能转换为其他类型(更具体地说,有关于转换盒装类型的规则)。由于编译器在编译时不知道 T 是什么,它必须谨慎行事并拒绝强制转换。
-
@BenVoigt 确实如此,但我不知道为什么需要
(object)... -
@KirkWoll 该问题的公认答案是“[T]他的编译器不知道 T 是字符串。因此,它不允许你转换。[...]你需要转换为对象,(任何 T 都可以转换为对象),然后从那里转换为字符串”。那有什么不同?编译器也不知道某些任意的
object是string......事实上,在我看来,“编译器不能保证X 是Y”首先是显式转换的重点!