Search code examples
c#inheritancepublicaccess-modifiersinternal

How to prevent an abstract class with public derived classes from being inherited in other assemblies?


I want to write something like the following:

    internal class InternalData
    {
    }

    public class PublicData
    {
    }

    abstract internal class Base {
        internal Base() { }

        private static InternalData CreateInternalDataFromPublicData(PublicData publicData)
        {
            throw new NotImplementedException();
        }

        abstract protected void DoProcess(InternalData internalData);

        public void Process(PublicData publicData)
        {
            InternalData internalData = CreateInternalDataFromPublicData(publicData);
            DoProcess(internalData);
        }
    }

    public sealed class Derived : Base
    {
        protected override void DoProcess(InternalData internalData)
        {
            throw new NotImplementedException();
        }
    }

That is, Base contains some internal logic and is not intended to be inherited by classes outside of my assembly; and Derived is accessible from the outside. InternalData also contains some internal logic and, as it would (and should) never be used from the outside, i also want to make it internal.

Of course the code above won't compile as the Base should not be less accessible than Derived. I can set the Base to be public, that's fine, but it leads to another problem. If Base is public, then there could possibly be some ExternalDerived : Base in some other assembly. But Base.DoProcess accepts an InternalData as its argument, so that ExternalDerived cannot implement it (as it doesn't know about the InternalData). Internal parameterless Base constructor prevents creation of any ExternalDerived instances, and thus nobody will implement ExternalDerived.DoProcess and no InternalData public exposure is needed, but the compiler doesn't know it.

How can i rewrite the code above so that there will be an abstract DoProcess(InternalData) method and so that InternalData class will be internal?


Solution

  • Set Base to be public.

    public abstract class Base {...
    

    Change Base.DoProcess:

    protected virtual void DoProcess<T>(T internalData)
    {
        if (!(internalData is InternalData))
        {
            throw new ArgumentOutOfRangeException("internalData");
        }
    }
    

    Change Derived.DoProcess:

    protected override void DoProcess<T>(T internalData)
    {
        base.DoProcess(internalData);
        // Other operations
    }