Реализация внутреннего интерфейса - PullRequest
17 голосов
/ 22 ноября 2011

Прямо к проблеме: у меня есть класс, который реализует два интерфейса:

public class A : Interface1, Interface2{
   // Interface 1 implementation...
   // Interface 2 implementation...
}

Есть ли способ (без создания другого нового класса) сделать реализацию Interface1 внутренней и скрыть ее от других компонентов (только Interface2 останется общедоступным)?

РЕДАКТИРОВАТЬ: Некоторые полезные сведения: Interface1 и Interface2 определены как общедоступные в другом базовом компоненте и не могут быть изменены.

Заранее спасибо,

Ответы [ 2 ]

35 голосов
/ 22 ноября 2011

Хотя вы можете сделать сам интерфейс внутренним, методы все равно будут частью общедоступного API. Вы можете выбрать явную реализацию интерфейса, так что API, определенный интерфейсом, виден только через интерфейс, а не через класс.

interface IFoo
{
     void M();
}

interface IBar
{
     void X(); 
}

public class Bar : IBar, IFoo
{
    public void X() // part of the public API of Bar
    {
    }

    void IFoo.M() // explicit implementation, only visible via IFoo
    {
    }
}

Bar bar = new Bar();
bar.X(); // visible
bar.M(); // NOT visible, cannot be invoked
IFoo foo = bar;
foo.M(); // visible, can be invoked

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

public class Bar : IBar
{
    Foo foo = new Foo();

    public void X() { }   

    public void DoSomething()
    {
        this.foo.M(); // invokes method of instance of nested class
    }

    class Foo : IFoo
    {
        public void M() { } 
    }
}

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

3 голосов
/ 22 ноября 2011

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

Например:

public class Foo
{
    private IFoo wrap = new WrapFoo(this);

    internal IFoo GetIFoo()
    {
        return wrap;
    }

    private class WrapFoo : IFoo
    {
        public WrapFoo(Foo parent)
        {
            //Save parent
        }

        public void DoSomething()
        {
            //Implement interface
        }
    }
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...