views:

64

answers:

2

This question is similar to c# internal abstract class, how to hide usage outside but my motiviation is different. Here is the scenario

I started with the following:

internal class InternalTypeA {...}

public class PublicClass
{
   private readonly InternalTypeA _fieldA;

   ...
}

The above compiles fine. But then I decided that I should extract a base class and tried to write the following:

public abstract class PublicBaseClass
{
   protected readonly InternalTypeA _fieldA;

   ...
}

And thus the problem, the protected member is visible outside the assembly but is of an internal type, so it won't compile.

The issue at hand is how to I (or can I?) tell the compiler that only public classes in the same assembly as PublicBaseClass may inherit from it and therefore _fieldA will not be expossed outside of the assembly?

Or is there another way to do what I want to do, have a public super class and a set of public base classes that are all in the same assembly and use internal types from that assembly in their common ("protected") code?

The only idea I have had so far is the following:

public abstract class PublicBaseClass
{
   private readonly InternalTypeA _fieldA;

   protected object FieldA { get { return _fieldA; } }

   ...
}

public class SubClass1 : PublicBaseClass
{
    private InternalTypeA _fieldA { get { return (InternalTypeA)FieldA; } } 
}

public class SubClass2 : PublicBaseClass
{
    private InternalTypeA _fieldA { get { return (InternalTypeA)FieldA; } } 
}

But that is UGLY!

+3  A: 

The CLR provides a FamilyAndAssembly accessibility which will do what you want, but there isn't the syntax in C# to use it.

The workaround is to make the variable field internal, and you'll have to trust the code in your assembly to not access it inappropriately.

You can also make the constructor of PublicBaseClass internal, so only your assembly can instantiate it. That way, only your classes can inherit off it (even if the class itself is public)

thecoop
Yep, FamilyAndAssembly is exactly what I want. I agree that using internal members is better than my hack above. Wonder why I didn't think of it. Probably because I so hate over-scoping things.Thanks for the info!
Kenneth Baltrinic
Ay, I find it quite annoying as well, but it's something we've got to live with unfortunately :(
thecoop
A: 

The cleanest way to deal with this is the use of public interfaces and private classes. If your refactoring existing code this is not always an option. One easy way to ease the pain of that conversion is to use a public abstract class instead of an interface and expose a static factory method.

Example:

public abstract class MyClass
{
    public static MyClass New()
    { return new InternalMyClass(); }
}

class InternalMyClass : MyClass
{ }
csharptest.net
This approach would not work because I need InternalMyClass to be a public type.
Kenneth Baltrinic