Странно странный полиморфизм интерфейса с использованием композиции интерфейса - PullRequest
5 голосов
/ 13 февраля 2009

Я получил что-то вроде следующего кода в проекте, над которым я работаю. Я думал, что это действительно странно, что мне разрешили это сделать, но теперь я начинаю задумываться, что, скорее всего, архитектурная ошибка с моей стороны, привела меня к этому.

Мои вопросы к вам:

  • Что именно это называется?
  • Какое использование этого в реальном мире?
  • Зачем кому-то это делать?

Вот мои интерфейсы:

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

    }
}

Ответы [ 2 ]

5 голосов
/ 13 февраля 2009

В этом коде нет ничего плохого (при условии, что он не сбивает с толку ваших пользователей), и это не шаблон с каким-либо именем, с которым я знаком. CanDoThisAndThat реализует два интерфейса, поэтому клиенты могут использовать его любым способом.

.NET позволяет реализовывать интерфейсы таким способом - известный как явная реализация интерфейса .

Явная реализация интерфейса полезна, когда:

  1. Два интерфейса имеют одинаковое определение элемента
  2. Вам необходимо реализовать интерфейс, но вы не хотите публиковать информацию о том, что конкретный элемент доступен клиентскому коду, который не объявил ссылку с использованием типа интерфейса

Пример случая 2 из .NET Framework - 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
{
    // ...
}
4 голосов
/ 13 февраля 2009

Каждый тип имеет отображение интерфейса (которое можно получить с помощью Type.GetInterfaceMap , если вы хотите посмотреть на него с отражением). Это в основном гласит: «Когда вызывается метод X на интерфейсе Y, этот метод Z вызывается». Обратите внимание, что, хотя это не поддерживается в C #, для метода назначения сопоставления может быть имя, отличное от имени метода интерфейса! (VB явно поддерживает это, я считаю.)

В вашем случае у вас есть три метода, и каждый из трех методов соответствует методу в одном из задействованных интерфейсов.

Когда компилятор выполняет вызов виртуального метода через интерфейс, сгенерированный IL говорит что-то вроде «вызовите IFoo.Bar для этого объекта» - и IFoo.Bar затем разрешается с использованием карты интерфейса.

Иногда вам может понадобиться использовать его, если у вас есть сигнатуры, которые отличаются только типом возвращаемого значения, или если вы реализуете два гетерогенных интерфейса, которые имеют одинаковые имена методов, но должны выполнять разные действия. Везде, где вы можете избегать этого, делайте! Это делает для очень запутанного кода.

...