C# - Can publicly inherited methods be hidden (e.g. made private to derived class)

前端 未结 10 1583
说谎
说谎 2020-12-04 19:00

Suppose I have BaseClass with public methods A and B, and I create DerivedClass through inheritance.

e.g.

public DerivedClass : BaseClass {}
<         


        
相关标签:
10条回答
  • 2020-12-04 19:22

    The only way to do this that I know of is to use a Has-A relationship and only implement the functions you want to expose.

    0 讨论(0)
  • 2020-12-04 19:24

    Hiding is a pretty slippery slope. The main issues, IMO, are:

    • It's dependent upon the design-time declaration type of the instance, meaning if you do something like BaseClass obj = new SubClass(), then call obj.A(), hiding is defeated. BaseClass.A() will be executed.

    • Hiding can very easily obscure behavior (or behavior changes) in the base type. This is obviously less of a concern when you own both sides of the equation, or if calling 'base.xxx' is part of your sub-member.

    • If you actually do own both sides of the base/sub-class equation, then you should be able to devise a more manageable solution than institutionalized hiding/shadowing.
    0 讨论(0)
  • 2020-12-04 19:34

    That sounds like a bad idea. Liskov would not be impressed.

    If you don't want consumers of DerivedClass to be able to access methods DeriveClass.A() and DerivedClass.B() I would suggest that DerivedClass should implement some public interface IWhateverMethodCIsAbout and the consumers of DerivedClass should actually be talking to IWhateverMethodCIsAbout and know nothing about the implementation of BaseClass or DerivedClass at all.

    0 讨论(0)
  • 2020-12-04 19:34

    If they're defined public in the original class, you cannot override them to be private in your derived class. However, you could make the public method throw an exception and implement your own private function.

    Edit: Jorge Ferreira is correct.

    0 讨论(0)
  • 2020-12-04 19:34

    While the answer to the question is "no", there is one tip I wish to point out for others arriving here (given that the OP was sort of alluding to assembly access by 3rd parties). When others reference an assembly, Visual Studio should be honoring the following attribute so it will not show in intellisense (hidden, but can STILL be called, so beware):

    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
    

    If you had no other choice, you should be able to use new on a method that hides a base type method, return => throw new NotSupportedException();, and combine it with the attribute above.

    Another trick depends on NOT inheriting from a base class if possible, where the base has a corresponding interface (such as IList<T> for List<T>). Implementing interfaces "explicitly" will also hide those methods from intellisense on the class type. For example:

    public class GoodForNothing: IDisposable
    {
        void IDisposable.Dispose() { ... }
    }
    

    In the case of var obj = new GoodForNothing(), the Dispose() method will not be available on obj. However, it WILL be available to anyone who explicitly type-casts obj to IDisposable.

    In addition, you could also wrap a base type instead of inheriting from it, then hide some methods:

    public class MyList<T> : IList<T>
    {
        List<T> _Items = new List<T>();
        public T this[int index] => _Items[index];
        public int Count => _Items.Count;
        public void Add(T item) => _Items.Add(item);
        [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
        void ICollection<T>.Clear() => throw new InvalidOperationException("No you may not!"); // (hidden)
        /*...etc...*/
    }
    
    0 讨论(0)
  • 2020-12-04 19:35

    It's not possible, why?

    In C#, it is forced upon you that if you inherit public methods, you must make them public. Otherwise they expect you not to derive from the class in the first place.

    Instead of using the is-a relationship, you would have to use the has-a relationship.

    The language designers don't allow this on purpose so that you use inheritance more properly.

    For example one might accidentally confuse a class Car to derive from a class Engine to get it's functionality. But an Engine is functionality that is used by the car. So you would want to use the has-a relationship. The user of the Car does not want to have access to the interface of the Engine. And the Car itself should not confuse the Engine's methods with it's own. Nor Car's future derivations.

    So they don't allow it to protect you from bad inheritance hierarchies.

    What should you do instead?

    Instead you should implement interfaces. This leaves you free to have functionality using the has-a relationship.

    Other languages:

    In C++ you simply specify a modifier before the base class of private, public or protected. This makes all members of the base that were public to that specified access level. It seems silly to me that you can't do the same in C#.

    The restructured code:

    interface I
    {
        void C();
    }
    
    class BaseClass
    {
        public void A() { MessageBox.Show("A"); }
        public void B() { MessageBox.Show("B"); }
    }
    
    class Derived : I
    {
        public void C()
        {
            b.A();
            b.B();
        }
    
        private BaseClass b;
    }
    

    I understand the names of the above classes are a little moot :)

    Other suggestions:

    Others have suggested to make A() and B() public and throw exceptions. But this doesn't make a friendly class for people to use and it doesn't really make sense.

    0 讨论(0)
提交回复
热议问题