5

在我正在处理的项目中,我最终得到了类似以下代码的内容。我认为我被允许这样做真的很奇怪,但现在我开始想知道我最有可能的建筑失误导致我这样做。

我对你的问题是:

  • 这到底叫什么?
  • 这在现实世界中有什么用途?
  • 为什么会有人想要这样做?

这是我的接口:

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

    }
}
4

2 回答 2

5

这段代码绝对没有问题(前提是它不会让您的用户感到困惑),而且它不是我熟悉的任何名称的模式。 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
{
    // ...
}
于 2009-02-13T07:21:45.647 回答
4

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

在您的情况下,您有三个方法,这三个方法中的每一个都对应于所涉及的接口之一中的一个方法。

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

如果您的签名仅在返回类型上有所不同,或者您正在实现两个恰好具有相同方法名称但应该做不同事情的异构接口,您有时可能需要使用它。但是,只要您可以避免它,就去做!它使代码非常混乱。

于 2009-02-13T07:13:17.603 回答