将一个接口强制转换成另一个未继承的接口

13
我希望有人能够解释一下我犯了哪些错误假设。在C# 4.0中,我有两个接口和一个实现它们的类。在一个方法中,我声明了一个类型为第一个接口的变量,并使用实现两个接口的类进行实例化,并可以将其成功地强制转换为第二个接口,就像下面的代码一样:
    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”,但转换仍然成功。

我错过了什么?

6个回答

10

从你的示例来看,在调用任何功能之前,你应该测试类型。第一个创建将创建一个完全合格的“InterfaceImplementation”,支持两个接口。但是,你将其放入了仅第一个接口声明类型的声明类型中。因此,从“第一个”对象的角度来看,它只关心与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();

这证实了我之前所想的事情。谢谢。 - fepiv

3
实际上,实例“first”指向的类型实现了两个接口。因此,对象上显然都可以使用“Method1”和“Method2”。
“first”的静态类型只允许访问“Method1”。 “second”的静态类型只允许访问“Method2”。如果您使用任一接口声明对对象的引用,则仅选择将实例视为符合所选合同(即接口)的对象。
由于“InterfaceImplementation”实现了两个接口,因此您可以使用任一接口引用该实例。

1

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


1
你唯一缺少的是这正是它应该的样子,而且这是一个有用的特性,而不是问题。在转换时,你可以将代码视为基本上在说:“我不关心我知道这个对象的类型是什么,我想看看它是否可以转换为类型T”。在这种情况下,由于底层对象是InterfaceImplementation类型,无论它当前被称为IFirstInterface,答案是肯定的,它可以转换为ISecondInterface

1

欢迎来到多态性。对象first始终是InterfaceImplementation的一个实例。您选择如何引用它不会影响对象真正的“本质”。这就是抽象概念整体运作的方式。


0

这实际上表明了一个设计缺陷。客户端有点知道这两个接口都是由同一个对象实现的。对于你的例子来说,这很好,但如果这些接口是分别实现的,你就无法从第一个跳转到第二个。理想情况下,最好有一种查询接口,可以从一种类型转到另一种类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接