将接口强制转换为它不继承的另一个接口

本文关键字:接口 继承 另一个 转换 | 更新日期: 2023-09-27 18:32:52

我希望这里有人能解释我所做的错误假设。在 C# 4.0 中,我有 2 个接口和一个实现这两个接口的类。在方法中,我声明了一个具有第一个接口类型的变量,使用实现两个接口的类实例化它,并且可以以某种方式将其成功强制转换为第二个接口,如以下代码所示:

    public interface IFirstInterface 
    {
        void Method1();
    }
    public interface ISecondInterface
    {
        void Method2();
    }
    public class InterfaceImplementation : IFirstInterface, ISecondInterface
    {
        public void Method1() { }
        public void Method2() { }
    }
    public class SomeClass
    {
        public void SomeMethod()
        {
            IFirstInterface first = new InterfaceImplementation();
            first.Method1();
            // Shouldn't the next line return null?
            ISecondInterface second = first as ISecondInterface; 
            // second is not null and the call to Method2() works fine
            second.Method2();
        }
    }

我试图理解为什么选角成功。是的,该类实现了这两个接口,但我认为由于第一个变量被声明为 IFirstInterface(它不继承自 ISecondInterface),因此转换仍然应该失败。

我也尝试过用其他方式重组我的代码,比如不使用"as",但强制转换仍然成功。

我错过了什么?

将接口强制转换为它不继承的另一个接口

从您的示例中,您应该在调用任何功能之前测试类型类型。第一次创建将创建一个完全限定的"接口实现",支持这两个接口。 但是,您将其放入仅第一个接口的声明类型中。 因此,从"第一个"对象的角度来看,它只关心与 IFirstInterface 实现相关的任何内容。

现在,接下来是你...即使您已经创建了对象,您仍然可以询问...顺便一提。。。您也是第二界面吗? 如果是这样,请执行此操作...

IFirstInterface first = new InterfaceImplementation();
if( first is ISecondInterface )
  // typecast since the second interface is legit, then call it's method 2
  ((ISecondInterface)first).Method2();

实例的实际类型first指向实现这两个接口。因此,显然Method1Method2都可以在对象上使用。

first的静态类型仅允许您访问Method1second的静态类型仅允许您访问Method2 。我使用任一接口声明对对象的引用,您只需选择将实例视为履行所选合约(接口)的对象。

由于InterfaceImplementation实现了这两个接口,因此您可以选择使用任一接口引用实例。

如果你从具体对象的角度来看,你可以说"我是一个IFirstInterface,但我也是一个ISecondInterface"。这是你的意思吗?您描述的问题最终会在继承/实现链中转换。

你唯一缺少的是,这正是它的意思,这是一个有用的功能,而不是问题。 在强制转换时,你可以将代码基本上想象成说,"我不在乎我知道这个对象的类型是什么,我想看看它是否可以转换为类型 T"。 在这种情况下,由于底层对象是 InterfaceImplementation 型 ,无论它目前被称为 IFirstInterface ,答案是肯定的,它可以转换为ISecondInterface

欢迎来到多态性。对象first始终是 InterfaceImplementation 的实例。您选择引用它的方式不会影响对象的真正"是什么"。这就是抽象概念作为一个整体的工作方式。

这确实表明存在设计缺陷。 客户端知道这两个接口是由同一个对象实现的。 对于您的示例,这很好,但如果这些接口是单独实现的,您将无法从第一个跳转到第二个接口。理想情况下,最好有某种查询接口,您可以在其中从一种类型转到另一种类型。