Что такое частный интерфейс?

В интервью некоторое время назад для позиции .NET интервьюер спросил меня: "Для чего вы используете частный интерфейс?".

Я спросил его, имел ли он в виду разницу между неявной vs явной реализацией интерфейса, на которую он ответил нет.

Итак, мне интересно:

  • Что он имел в виду?
  • Что вы бы использовали для частного интерфейса?

Ответ 1

Интерфейс может быть закрытым в другом классе

public class MyClass
{
    private interface IFoo
    {
        int MyProp { get; }
    }

    private class Foo : IFoo
    {
        public int MyProp { get; set; }
    }

    public static void Main(string[] args)
    {
        IFoo foo = new Foo();
        return foo.MyProp;
    }
}

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

Явная реализация интерфейса - это другое дело, имеет некоторые очень полезные случаи (особенно при работе с дженериками и более старыми непиговыми интерфейсами), но я бы не называйте это "частным интерфейсом" и не сказал бы, что этот термин обычно используется таким образом.

Используя два метода вместе, вы можете:

public class MyClass
{
    private interface IFoo
    {
        int MyProp { get; }
    }

    public class Foo : IFoo
    {
        int IFoo.MyProp { get; set; }
    }

    public static void Main(string[] args)
    {
        IFoo foo = new Foo();
        return foo.MyProp;
    }
}

public class HiddenFromMe
{
    public static void Main(string[] args)
    {
        MyClass.Foo foo = new MyClass.Foo();
        return foo.MyProp; // fails to compile
    }
}

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

Ответ 2

От эта ссылка.

Наследование частного интерфейса

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

Наследование частного интерфейса - это просто способ скрыть методы из публичного API типов. Они скомпилированы в частные методы, но фактически доступны через карту интерфейсов типов. Другими словами, их можно вызвать только через ссылку, введенную в качестве интерфейса, на котором определен метод. Пример облегчит это понимание:

class PrivateImplementer : IFoo
{
   void IFoo.Foo()
   {
       Console.WriteLine("PrivateImplementer::IFoo.Foo");
   }
}

В этом случае PrivateImplementer общеизвестно реализовать IFoo. Таким образом, экземпляр можно обрабатывать полиморфно как экземпляр IFoo. Но на самом деле вы не можете называть Foo, если вы не рассматриваете его как IFoo. Этот код демонстрирует это:

PrivateImplementer p = new PrivateImplementer();
p.Foo(); // This line will fail to compile
IFoo f = p;
f.Foo();

Вы можете выбрать индивидуальные методы интерфейса для индивидуального использования. Например, если PrivateImplementer реализован IFooBar, он может предпочесть реализовать Foo конфиденциально, но Bar публично использует обычный синтаксис.

На практике существует множество распространенных случаев, когда вы будете использовать частную реализацию. Библиотека System.Collections.Generic использует этот подход для тайного внедрения всех устаревших интерфейсов System.Collections с слабо типизированными интерфейсами. Это делает обратную совместимость "просто работать", например, передавая экземпляр List<T> методу, который ожидает, что IList будет работать нормально. В этом конкретном примере загромождение API нового типа было бы очень жалким (существует множество методов, необходимых для слабо типизированной интероперабельности).

"Нет", это довольно плохой ответ, если он хочет узнать, что вы знали. Похоже на тех, кто просто хочет показать, насколько они знают.

Ответ 3

ShuggyCoUk дает хороший ответ, но с таким комментарием

Это потенциально полезный случай, но это не то, что я хотел бы использовать очень часто. Конечно, он использует в интервью, как будто это граничный случай, который использует интервьюер, потому что он его видел, и хотя это было "интересно"

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

Вот Реализация Full State Machine (FSM) с поддержкой наследования и поддержки узлов, что является хорошим примером использования частных/защищенных интерфейсов.

Это был ответ на вопросы Что такое эквивалент С# друга? и Почему С# не предоставляет стиль С++ 'friend' ключевое слово? и, фактически, на ваш вопрос тоже.

Ответ 4

Как и внутренний класс (который также является приватным), вы можете использовать частный интерфейс в существующем классе.

Ответ 5

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

Я не думаю, что это можно применить к С# tho, потому что тот же эффект IMO может быть достигнут с явными интерфейсами и клиентами, которые используют хост для соответствующего интерфейса.

Может, кто-то еще увидит то, что я там пропустил....

Я также нашел это на MSDN:

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