13

我希望这里有人可以解释我所做的错误假设。在 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',但演员仍然成功。

我错过了什么?

4

6 回答 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();
于 2012-05-02T17:56:05.347 回答
3

实例的实际类型first指向实现这两个接口。所以很明显两者Method1Method2在对象上都可用。

的静态类型first只允许您访问Method1. 的静态类型second只允许您访问Method2. 如果您使用任一接口声明对对象的引用,您只需选择将实例视为满足所选合同(接口)的对象。

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

于 2012-05-02T17:54:23.577 回答
1

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

于 2012-05-02T17:46:51.380 回答
1

您唯一缺少的是,这正是它的本意,这是一个有用的功能,而不是问题。转换时,您可以将代码视为基本上是在说,“我不在乎我知道这个对象的类型是什么,我想看看它是否可以转换为类型 T”。在这种情况下,由于基础对象的类型是InterfaceImplementation,不管它目前被称为 an IFirstInterface,答案是肯定的,它可以转换为 an ISecondInterface

于 2012-05-02T17:49:30.730 回答
0

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

于 2012-05-02T17:51:30.137 回答
0

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

于 2020-03-11T15:42:52.290 回答