界面铸造类型安全

时间:2015-12-16 09:28:06

标签: c# casting type-conversion

类型安全可防止在编译类型期间发生意外的转换。如何为继承的接口实现相同的编译时类型安全性?

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;
    }
}

5 个答案:

答案 0 :(得分:2)

你不能,也不应该 - 因为它可能不是一个错误。考虑额外的课程:

class BarBase : IBase, IBar
{
}

现在:

IBase item = new BarBase();
IBar bar = item as IBar;

这将bar保留为非空引用 - 那么为什么要将它作为编译时错误?请注意,编译器不应该/不注意:

  • 您如何初始化item
  • 是否有任何实现IBaseIBar
  • 的类

注意这种转换是否有效。考虑:

public sealed class Sealed {}
public interface IFoo {}

Sealed x = null;
IFoo foo = x as IFoo; // Error

此处有{em>否可能实现Sealed的{​​{1}}非空值,因为IFoo不能实现任何子类Sealed接口......所以编译器会出错。

答案 1 :(得分:1)

你做不到。编译器不知道实现IBaseIFoo的类型也不实现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对象可以是一个实现两个接口(IBaseIBar)的类,因此这种转换完全正常。

class MyImplementation : IBase, IFoo, IBar {
}

IBase x = new MyImplementation();
IBar bar = x as IBar; // valid