Частично защищенный интерфейс, но без абстрактного класса - PullRequest
2 голосов
/ 05 июля 2010

У меня следующий код.И мне нужно скрыть одну функцию интерфейса.

interface IOne
{
    int FunctionOne();
}

interface ITwo
{
    double FunctionTwo();
}

interface IInterfaceToImplement : IOne, ITwo
{
    void AFunctionToImplement();
}

public abstract MyBaseClass : TheVeryHeavyBaseClass<T, IInterfaceToImplement>, IInterfaceToImplement
{
    public abstract void AFunctionToImplement(); // How to force this one to be protected?

    public virtual int FunctionOne() { return 0; }

    public virtual double FunctionTwo() { return 0.0; }
}

public MyConcreteClass : MyBaseClass
{
    public override void AFunctionToImplement(); // How to force this one to be protected?
}

Как видите, у меня есть базовый класс.И мне нужно, чтобы AFunctionToImplement() было спрятано.У меня плохой дизайн классов?Любые предложения о том, как защитить функцию от вызова?

РЕДАКТИРОВАТЬ.Ответ на вопрос Павла Минаева в комментариях.

Мне нужно, чтобы каждый конкретный класс реализовывал список функций из IInterfaceToImplement.Также мне нужен каждый конкретный класс, чтобы иметь возможность хранить классы типа IInterfaceToImplement. Это древовидное хранилище данных. Каждая «ветвь» хранилища должна выполнять те же операции, что и любая другая ветвь.Но никто, кроме «корня» и других «веток», не должен называть эти операции.

EDIT2 Мое решение.

Спасибо Мэтью Эбботу и Павлу МинаевуЯ наконец осознал свою проблему - это мозг.:)

Нет, я шучу.:) Проблема в том, что я думал о корневых и отраслевых классах как об одной и той же ветке.Теперь я понимаю - рут не должен реализовывать IInterfaceToImplement.Смотрите решение:

public class MyRootClass : IOne, ITwo
{
    private IInterfaceToImplement internalData = new MyConcreteClass();

    public int FunctionOne() { return this.internalData.FunctionOne(); }

    public double FunctionTwo() { return this.internalData.FunctionTwo(); }
}

Ответы [ 5 ]

2 голосов
/ 05 июля 2010

Я бы предложил использовать явную реализацию интерфейса:

void IInterfaceToImplement.AFunctionToImplement();

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

Ваша лучшая ставка, это что-то вроде следующего:

public interface IMyInterface
{
    void DoWork();
}

public abstract class MyInterfaceBase : IMyInterface
{
    /// <summary>
    /// Forced implementation.
    /// </summary>
    protected abstract void DoWork();

    /// <summary>
    /// Explicit implementation.
    /// </summary>
    void IMyInterface.DoWork()
    {
        // Explicit work here.

        this.DoWork();
    }
}

Это все еще оставляет проблемы публичной демонстрации DoWork, еслиметод вызывается из ссылки IMyInterface, а не из ссылки MyInterfaceBase.Вы просто не можете обойти это.Если бы я сделал следующее:

MyInterface first = new MyInterface(); // Let's assume I have implemented MyInterface : MyInterfaceBase
first.DoWork(); // Compile error, can't access method here.

Принимая во внимание:

IMyInterface second = new MyInterface();
second.DoWork(); // No problem.

Можете ли вы увидеть проблему?

1 голос
/ 12 июля 2010
public class MyRootClass : IOne, ITwo
{
    private IInterfaceToImplement internalData = new MyConcreteClass();

    public int FunctionOne() { return this.internalData.FunctionOne(); }

    public double FunctionTwo() { return this.internalData.FunctionTwo(); }
}
1 голос
/ 05 июля 2010

Может быть, вы могли бы сделать метод виртуальным в абстрактном классе и затем выдать исключение

    /// <summary>
    /// Available only in derived classes
    /// </summary>
    public virtual void AFunctionToImplement2()
    {
        throw new ProtectedMethodException("Please do not call this method in the base class:) ");
    }

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

1 голос
/ 05 июля 2010

Всякий раз, когда вы пишете интерфейс, вы неявно объявляете публичное представление любого класса, который его реализует, поэтому вообще не имеет смысла пытаться скрыть его методы.Вы можете удалить AFunctionImplementation из интерфейса и оставить его включенным в классе MyBase.Любая реализация класса MyBase будет по-прежнему иметь к нему доступ.

В этом случае вы также можете заставить класс MyBase напрямую реализовывать IOne и ITwo.

Имея функцию со словом «Реализация» как частьего название было бы хорошим советом, чтобы не помещать его в интерфейс, так как интерфейсы часто используются как средство изоляции использования от деталей реализации.

1 голос
/ 05 июля 2010

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

public abstract MyBaseClass<T> : TheVeryHeavyBaseClass<T> 
{ 
    // remove the interface the defined this
    protected abstract void AFunctionToImplement(); 

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