tags:

views:

1899

answers:

6

I have a common assembly/project that has a 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 from using code in intellisense so I thought I'd make it internal, I get the error:

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

I don't really get this, I have to make the abstract settings class public and thus visible outside this assembly. How can I acheive this?

Thanks

+4  A: 

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

thecoop
Whats with the downvote?
thecoop
+10  A: 

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.

Rex M
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.
m3ntat
@m3ntat see my edited answer.
Rex M
You _cannot_ make base classes less accessible than derived classes. You _can_ make the base class members (but not the class itself) internal instead.
thecoop
@thecoop exactly!
Rex M
+1 Very clever!
Andrew Hare
A: 

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.

Chris Marisic
+1  A: 

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.

LBushkin
EditorBrowsableAttribute is only valid on class members, not class declarations.
Rex M
This is what I am looking for, but it doesn't seem to respect this in Intellisense I just tried.
m3ntat
Also, marking the class abstract prevents it from being instantiated. Having a protected default constructor does not.
Rex M
The OP indicated that he has an abstract class - my examples simply reflect that case.
LBushkin
@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.
Rex M
A: 

Will the other assemblies ever inherit from your abstract base class or any of the public classes that do inherit from your abstract base class?

If so, you have to make the abstract base class public. Just make methods you don't want visible outside the assembly internal.

If not, maybe interfaces can help? Define public interfaces, make your public classes implement them, and provide a factory to get instances. That way the only thing intellisense sees outside the assembly is the interface.

Does that help?

n8wrl
A: 

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.

Joel B Fant