简体   繁体   中英

Partially protected interface but without abstract class

I have following code. And I need to hide one function of the interface.

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?
}

As you can see I have base class. And I need the AFunctionToImplement() to be hidden. Do I have poor classes design? Any suggestions on how to protected the function from being called?

EDIT. Answer to Pavel Minaev question in the comments.

I need every concrete class implement the list of functions from IInterfaceToImplement. Also I need every concrete class to be able to store classes of IInterfaceToImplement type. This is tree-like data storage. Every 'branch' of the storage have to perform same operations as any other branch. But nobody else except the 'root' and other 'braches' must call these operations.

EDIT2 My solution.

Thanks Matthew Abbott and Pavel Minaev. I finally realized my problem - it is brain. :)

No, I'm joking. :) The problem is - I thought of root and branch classes as of the same branch. Now I understand - the root should not implement IInterfaceToImplement . See the solution:

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

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

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

I would suggest using an explicit interface implementation:

void IInterfaceToImplement.AFunctionToImplement();

...but that wouldn't allow you to expose and implement the method in subclasses and still have it hidden. You may want to rethink your class design in this case.

Your best bet, it something like the following:

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

This still leaves the issues of having the DoWork publicly exposed if the method is called from an IMyInterface reference, instead of a MyInterfaceBase reference. You simply can't get round this. If I did the following:

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

Whereas:

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

Can you see the issue?

Interfaces can only be defined for public members. If you want a method to only be defined as protected then don't make an interface for it and just create it as a protected abstract member of the abstract base class. Even if you were to use the explicit interface it would still be publicly accessible if the instance is case to the related interface type.

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

    // other code
} 

Whenever you write an interface you're implicitly declaring a public view of any class that implements it, so it wouldn't make sense at all to try and hide its methods. You can take AFunctionImplementation out of the interface and leave it live in MyBase class. Any implementation of MyBase class would still have access to it.

In this case you can also make MyBase class implement IOne and ITwo directly.

Having a function with the word 'Implementation' as part of its name would be a good hint to avoid putting it in an interface, as interfaces are often used as a means to isolate usage from implementation details.

Maybe you could make the method virtual in the abstract class and then throw an exception

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

I don't know if this is a silly solution, but at least you don't allow the users to use the method even if it's public.

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

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM