繁体   English   中英

使用接口组合的奇怪的界面多态性

[英]Freakishly weird interface polymorphism using interface composition

我在一个正在研究的项目中得到了类似下面代码的东西。 我觉得我被允许这样做真的很奇怪,但是现在我开始想知道我最有可能是一个建筑师,这让我想到了这一点。

我的问题是:

  • 究竟是什么叫做?
  • 这有什么现实世界的用途?
  • 为什么有人想要这样做?

这是我的界面:

namespace ThisAndThat
{
    public interface ICanDoThis
    {
        string Do();
    }

    public interface ICanDoThat
    {
        string Do();
    }

    public interface ICanDoThisAndThat : ICanDoThis, ICanDoThat
    {
        new string Do();
    }
}

这是我的具体课程:

namespace ThisAndThat
{
    public class CanDoThisAndThat : ICanDoThisAndThat
    {
        public string Do()
        {
            return "I Can Do This And That!";
        }

        string ICanDoThis.Do()
        {
            return "I Can Do This!";
        }

        string ICanDoThat.Do()
        {
            return "I Can Do That!";
        }
    }
}

我的通过考试:

using Xunit;

namespace ThisAndThat.Tests
{
    public class ThisAndThatTests
    {
        [Fact]
        public void I_Can_Do_This_And_That()
        {
            ICanDoThisAndThat sut = new CanDoThisAndThat();

            Assert.Equal("I Can Do This And That!", sut.Do());
        }

        [Fact]
        public void I_Can_Do_This()
        {
            ICanDoThis sut = new CanDoThisAndThat();

            Assert.Equal("I Can Do This!", sut.Do());
        }

        [Fact]
        public void I_Can_Do_That()
        {
            ICanDoThat sut = new CanDoThisAndThat();

            Assert.Equal("I Can Do That!", sut.Do());
        }

    }
}

这段代码绝对没有错(前提是它不会让你的用户感到困惑),而且它不是一个我熟悉的任何名字的模式。 CanDoThisAndThat实现了两个接口,因此客户端可以以任何一种方式使用它。

.NET允许以这种方式实现接口 - 称为显式接口实现

在以下情况下显式接口实现很有用:

  1. 两个接口具有相同的成员定义
  2. 您需要实现一个接口,但不希望公开特定成员可用于未使用接口类型声明引用的客户端代码

.NET框架中的案例2的示例是ICollection.SyncLock List<T>实现ICollection但是以下代码将无法编译,因为该成员故意被“隐藏”,因为BCL的设计者不再提倡以这种方式锁定集合:

List<object> list = new List<object>();

lock (list.SyncRoot) // compiler fails here
{
    // ...
}

此格式的任何遗留代码仍然有效,因为引用的类型为ICollection

ICollection list = new List<object>();

lock (list.SyncRoot) // no problem
{
    // ...
}

每种类型都有一个接口映射 (如果你想用反射来查看它,可以用Type.GetInterfaceMap检索它)。 这基本上说,“当调用接口Y上的方法X时,此方法Z是要调用的方法。” 请注意,即使C#中不支持它,映射目标方法也可能与接口方法名称具有不同的名称! (我相信VB明确支持这一点。)

在您的情况下,您有三种方法,三种方法中的每一种都对应于其中一个接口中的方法。

当编译器通过接口发出对虚方法的调用时,生成的IL表示“在此对象上调用IFoo.Bar” - 然后使用接口映射解析IFoo.Bar。

如果您的签名只有返回类型不同,或者您实现的两个异构接口碰巧具有相同的方法名称但应该执行不同的操作,则有时可能需要使用它。 无论你哪里可以避免它,做! 它使代码非常混乱。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM