Internal abstract class: how to hide usage outside assembly?

25,084

Solution 1

As I understand, you want your abstract class to only be implemented by other classes in the same assembly (e.g. it is internal) but the derived classes could be public.

The way to do this is to make the abstract base class public, but give it an internal default constructor:

public abstract class MyClass
{
    internal MyClass() { }
}

This will allow MyClass (and hence its members) to be visible and usable to classes outside your assembly, but classes outside your assembly cannot inherit from it (will get a compile error).

Edit: If classes which can be seen by external assemblies inherit from MyClass, you cannot prevent MyClass from also being seen - e.g., showing up in Intellisense. However, you can prevent them from being used by following the above.

Solution 2

The abstract base class has to be public, as the entire inheritance heirarchy for a class has to be visible. This ensures the polymorphism works and is valid; however all the base classes' members can be internal (including the constructor), and hence not usable outside your assembly

Solution 3

There really isn't much of a benefit to what you're trying to achieve but what you're actually looking to achieve is similar to this.

Have your abstract base class in 1 assembly with everything internal. In the AssemblyInfo for that assembly you need to add

[assembly:InternalsVisibleTo("cs_friend_assemblies_2")]

Then in another assembly you have all the classes you want publicly available. Note you will still be able to access the base class from intellisense for any code inside cs_friend_assemblies_2 or whatever you name your assembly but not any where else.

Solution 4

You can't simultaneously make the class available to other assemblies for inheritance but also private so it can't be visible to other consumers. You can make the class internal, and expose it to a specific assembly (if it's a friend assembly) using the [InternalsVisibleTo] attribute, but I don't think this is what you want.

If you want to keep code (other than derived classes) from being able to instantiate your base class, you could give it a protected constructor:

abstract class MyBaseClass
{
    protected MyBaseClass() { ... } // only inheritors can access this...
}

You can hide the class members from Intellisense using the EditorBrowsable attribute:

abstract class MyBaseClass
{ 
    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
    public void SomeMethodToBeHidden() { }
}

It should be noted that some people have reported problems with the IDE not always respecting this attribute.

Solution 5

As far as I'm concerned, this is a non-problem. Observe:

public abstract class Foo {
    public void virtual Bar() {
        // default implementation
    }
}

public class NormalFoo : Foo { }

public class SpecialFoo : Foo {
    public override void Bar() {
        // special implementation
    }
}

var foolist = new List<Foo>();

foolist.Add( new NormalFoo() );
foolist.Add( new SpecialFoo() );

foreach (var f in foolist) {
    f.Bar();
}

The above wouldn't work at all without polymorphism -- being able to refer to instances of different derived classes through their common interface, the abstract base class. What you want to do is take that away and cripple the usability of your class hierarchy. I don't think you should continue down this path.

Share:
25,084
m3ntat
Author by

m3ntat

c# developer -windows forms -asp.net webforms -sql databases -oracle databases

Updated on November 18, 2020

Comments

  • m3ntat
    m3ntat over 3 years

    I have a common assembly/project that has an abstract base class, then several derived classes that I want to make public to other assemblies.

    I don't want the abstract base class to show up in these other assemblies in Intellisense, so I thought I'd make it internal, but I get this error:

    Inconsistent accessibility: base class 'Settings' is less accessible than class 'IrcSettings' ....

    I don't really get this. I am forced to make the abstract Settings class public, and thus visible outside this assembly.

    How can I make this class internal instead?

  • JonDrnek
    JonDrnek almost 15 years
    EditorBrowsableAttribute is only valid on class members, not class declarations.
  • m3ntat
    m3ntat almost 15 years
    This is what I am looking for, but it doesn't seem to respect this in Intellisense I just tried.
  • JonDrnek
    JonDrnek almost 15 years
    Also, marking the class abstract prevents it from being instantiated. Having a protected default constructor does not.
  • m3ntat
    m3ntat almost 15 years
    My question is not about missue. I've already prevented that. It's about not polluting the Intellisense with a Class that is unusable outside the assembly.
  • LBushkin
    LBushkin almost 15 years
    The OP indicated that he has an abstract class - my examples simply reflect that case.
  • JonDrnek
    JonDrnek almost 15 years
    @LBushkin that's fine, but having a protected default constructor on an abstract class does not actually do anything - the class already cannot be instantiated because it's abstract and the accessibility of the constructor is already restricted to deriving classes by that fact.
  • thecoop
    thecoop almost 15 years
    You cannot make base classes less accessible than derived classes. You can make the base class members (but not the class itself) internal instead.
  • Letseatlunch
    Letseatlunch about 13 years
    i think this is the only suggestion for the OP to ACTUALLY achieve what he wants although this is a pretty awful method, but still +1
  • Chris Marisic
    Chris Marisic about 13 years
    I might not find value in what the OP wants to achieve but I wouldn't say this is an awful approach. This basically opens up "friend assemblies" in .NET. Friend assemblies used in wrong situations can lead to awful code and awful frameworks but that would be from bad practices. I find the most needed use of friend assemblies is for test projects and sometimes in ServiceLayer dependencies (ex UpdatedBy is { public get; internal protected set } and the Service is allowed to assign UpdatedBy but no where else is).
  • Letseatlunch
    Letseatlunch about 13 years
    i came across this question because i had a similar need to the OP and found yours to be the only that would actually work for the OP. In my case, however, it would Not work for certain reasons and this was not an option. So i wouldn't call this an "Awful" solution either, that IS an exaggeration but it did feel this is more like a shechy work around that won't work in all cases.
  • Suzanne Soy
    Suzanne Soy almost 11 years
    Unless I'm mistaken, this has nothing to do with polymorphism: A class can implement an internal interface, and turning that interface into an abstract class changes nothing in to way the methods are inherited etc., for that matter. Theoretically, one could perfecly well define a class which has an internal base class, and use it in other assemblies. It's just that C# (or .NET ?) doesn't allow that.