Принудительное использование интерфейса вместо конкретной реализации в объявлении (.NET) - PullRequest
6 голосов
/ 05 мая 2010

В C ++ вы можете делать следующее:

class base_class
{
public:
    virtual void do_something() = 0;
};

class derived_class : public base_class
{
private:
    virtual void do_something()
    {
        std::cout << "do_something() called";
    }
};

derived_class переопределяет метод do_something() и делает его private. В результате единственный способ вызвать этот метод таков:

base_class *object = new derived_class();
object->do_something();

Если вы объявляете объект типа derived_class, вы не можете вызвать метод, потому что он закрытый:

derived_class *object = new derived_class();
object->do_something(); 
// --> error C2248: '::derived_class::do_something' : cannot access private member declared in class '::derived_class'  

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

Поскольку в C # / .NET в целом вам не разрешено сужать доступ с public до private при переопределении метода, есть ли способ добиться подобного эффекта здесь?

Ответы [ 4 ]

14 голосов
/ 05 мая 2010

Если вы явно реализуете интерфейс, это, по крайней мере, побудит людей использовать тип интерфейса в объявлении.

interface IMyInterface
{
    void MyMethod();
}

class MyImplementation : IMyInterface
{
    void IMyInterface.MyMethod()
    {
    }
}

MyMethod будет виден только после приведения экземпляра к IMyInterface. Если в объявлении используется тип интерфейса, при последующих использованиях преобразование не требуется.

Страница MSDN о явной реализации интерфейса (спасибо, Люк, спасает меня несколько секунд ^^)

IMyInterface instance = new MyImplementation();
instance.MyMethod();

MyImplementation instance2 = new MyImplementation();
instance2.MyMethod();  // Won't compile with an explicit implementation
((IMyInterface)instance2).MyMethod();
4 голосов
/ 05 мая 2010

Вы можете сделать это и в мире .Net, используя явную реализацию интерфейса

Например, BindingList<T> реализует IBindingList, но вы должны привести его к IBindingList, чтобы увидеть метод.

2 голосов
/ 05 мая 2010

Вы можете уменьшить доступность метода, пометив его как new.

Пример из MSDN CA2222: не уменьшать видимость унаследованных членов :

using System;
namespace UsageLibrary
{
    public class ABaseType
    {
        public void BasePublicMethod(int argument1) {}
    }
    public class ADerivedType:ABaseType
    {
        // Violates rule: DoNotDecreaseInheritedMemberVisibility.
        // The compiler returns an error if this is overridden instead of new.
        private new void BasePublicMethod(int argument1){}       
    }
}

Это действительно более интересно как академическое упражнение; если ваш код действительно зависит от невозможности вызова BasePublicMethod на ADerivedType, это предупреждающий знак сомнительного дизайна.

0 голосов
/ 05 мая 2010

Проблема этой стратегии, если она будет реализована, заключается в том, что метод не является действительно закрытым. Если вам нужно было отправить ссылку на base_class, то этот метод теперь общедоступен. Поскольку это виртуальный метод, код пользователя будет выполняться derived_class::do_something(), даже если он помечен как закрытый.

...