类型安全可防止在编译类型期间发生意外的转换。如何为继承的接口实现相同的编译时类型安全性?
public interface IBase { }
public interface IFoo : IBase { }
public interface IBar { }
public class Base { }
public class Foo : Base { }
public class Bar { }
public class Test
{
public void TestInterface()
{
IBase item = null;
IFoo foo = item as IFoo;
// How to get an error?
IBar bar = item as IBar;
}
public void TestClass()
{
Base item = null;
Foo foo = item as Foo;
// Error since Bar is not derived from Base
Bar bar = item as Bar;
}
}
答案 0 :(得分:2)
你不能,也不应该 - 因为它可能不是一个错误。考虑额外的课程:
class BarBase : IBase, IBar
{
}
现在:
IBase item = new BarBase();
IBar bar = item as IBar;
这将bar
保留为非空引用 - 那么为什么要将它作为编译时错误?请注意,编译器不应该/不注意:
item
IBase
和IBar
将注意这种转换是否有效。考虑:
public sealed class Sealed {}
public interface IFoo {}
Sealed x = null;
IFoo foo = x as IFoo; // Error
此处有{em>否可能实现Sealed
的{{1}}非空值,因为IFoo
不能实现任何子类Sealed
接口......所以编译器会出错。
答案 1 :(得分:1)
你做不到。编译器不知道实现IBase
和IFoo
的类型也不实现IBar
。它不是类继承,它不可能从多个派生出来。
如果item
是此类的一个实例,该怎么办?
public class BarAndFoo : IBar, IFoo { }
答案 2 :(得分:1)
C#中不允许多重继承,因此从Base
派生的类不可能转换为Bar
。
但是一个类可以实现多个接口。因此,IBase
引用引用的对象可能是同时实现IBar
的类的实例。在这种情况下,演员阵容将有效。
public class BarFoo : IBar, IFoo { }
IBase item = new BarFoo();
IFoo foo = item as IFoo;
IBar bar = item as IBar;
答案 3 :(得分:1)
如果您尝试编译以下代码,编译器将能够抛出错误:
IFoo foo = null;
IBar bar = foo; // Invalid cast at compile-time
当您使用as
运算符时,您告诉编译器将 保留为并让运行时确定转换是否有效,以及它是否无效它设置了null
。
如果您希望在这些情况下出现编译时错误,请查看Code Contracts并始终使用断言:
IFoo foo = new Foo();
IBar bar = foo as IBar;
Contract.Assert(bar != null);
...并启用静态合同检查,Code Contracts编译器将在编译时根据您的项目设置抛出警告或错误:
代码合同包括用于标记代码的类,静态代码 用于编译时分析的分析器和运行时分析器。该 代码合同的类可以在 System.Diagnostics.Contracts名称空间。
答案 4 :(得分:0)
请记住,item
对象可以是一个实现两个接口(IBase
和IBar
)的类,因此这种转换完全正常。
class MyImplementation : IBase, IFoo, IBar {
}
IBase x = new MyImplementation();
IBar bar = x as IBar; // valid