5

While expressing concern with preventing exposure of base classes, I learned (through testing) that a public class cannot inherit from an internal class; however, a public class can inherit from an internal interface. I am truly curious as to why this is possible. I believe it could be due to one of (or any combination of) the following:

  1. An interface simply contains signatures that must be implemented.
  2. A class may have properties, methods, etc. that can be accessed via the derived type.
  3. A class may have methods that can be overridden by derived types.

Case 1

I believe that since an interface is simply a contract that contains signatures and states that derived types must implement those signatures, the inheritance is allowed. This is due to the fact that the interface doesn't care who accesses these signatures, only that the derived type implements them.


Case 2 and 3

Unlike interfaces, classes can have public properties that can be accessed by derived types. For example:

private class A {
    public int SomeProperty { get; set; } = 0;
}
public class B : A {
    // Some cool code.
}
public class C : B {
    public int MyInt => SomeProperty;
}

This structure has inconsistent accessibility since SomeProperty is public and can be accessed by all derived types; thus A and B must have the same access levels to prevent exposure.


Is this the reason why a public class can derive from an internal interface but not a internal class, or am I missing something? Also, are there any other reasons why this is possible?


Note

I am not looking for an opinion based answer; I am looking for the technically correct reason why this is possible.

This is not a duplicate as I wanted the reason why you can't derive from one, but you can another.

Hazel へいぜる
  • 2,751
  • 1
  • 12
  • 44
  • Note: a public class *cannot* drevive from an implicitly implemented internal interface. – user2864740 Oct 16 '18 at 20:39
  • https://stackoverflow.com/a/3628062/2612547 – CSharper Oct 16 '18 at 20:41
  • Seems to side-step the question a bit.. a public class is not allowed to implement an internal class *even if* none of the internal class members are non-internal. So the restriction happens before (and more generally) than substitution. – user2864740 Oct 16 '18 at 20:42
  • @CSharper Though that was a good read, it really didn't answer my question. – Hazel へいぜる Oct 16 '18 at 20:44
  • @user2864740 So if I'm understanding you correctly, the `public class` would have to explicitly implement the interface in order to work? – Hazel へいぜる Oct 16 '18 at 20:45
  • @PerpetualJ That is correct: all the interface members must be explicitly implemented for the internal interface to not 'bleed' as a public dependency. Which is one of the main reasons "all" my (non-public) interfaces are explicitly implemented.. – user2864740 Oct 16 '18 at 20:45
  • The client code that uses the class does not need the interface to get its job done. All it uses is the class definition and the inherited base members. The latter is the rub, they have to be accessible as well. The C# syntax choice was unfortunate, you never "inherit" an interface. Inheritance is supposed to make you richer, an interface makes you a lot poorer since all you got was the demand to implement it. – Hans Passant Oct 16 '18 at 22:29

1 Answers1

1

I think that the key concept you are missing is the difference between inheritance and interface implementation.

When a class inherits another class, it means it's basically a more specific type of the base class - for instance, a dog is a specific type of an animal, so when you have classes like these:

class Animal {/* implementation here */}
class Dog : Animal {/* dog implementation here */}

The Dog class already contains all the implementation of the Animal, except it's constructors (static and instance) and Finalizers.

However, when a class implements an interface, it means that it must provide the members of said interface (namely method, properties, events and indexers), so if you have an IAnimal interface and a Dog class implementing it directly, your code looks like this:

interface IAnimal 
{
    void Eat();
}

class Dog : IAnimal 
{
    public void Eat() {/* implementation here */}
}

Note that everything that the IAnimal is declaring must be implemented, explicitly or implicitly, in the Dog class - so the contract provided by the interface is preserved in the class - regardless of whether the user of the class knows the interface or not.

So in conclusion - To use the class you don't need to know anything about the interfaces it implements, but you do need to know everything that is the class, and since a Dog IS an Animal, if the Dog is public, so must be the Animal.
The IAnimal interface, on the other hand, can stay internal.

One more point about implementing internal interfaces, already mentioned on the comments to the question by user2864740 - Since all implicit interface implementations must be public - if you are implementing an internal interface, you should consider implementing it explicitly - this way the implementation stays internal and is not exposed outside of the containing assembly.

Zohar Peled
  • 79,642
  • 10
  • 69
  • 121