Sunday, February 13, 2011

C# "internal" access modifier: I don’t think that means what you think that means

I’ve seen the “internal” access modifier used and abused on countless occasions, so I’d like to take the time disseminate its actual meaning along with ways it can be used.
 
Here’s the official documentation on the subject.
 
Here’s the short version :
  • The “internal” access modifier hides types and methods to anybody referencing your assembly; within the same assembly it is the same as “public”
  • Leaving off the “public” access modifier at the type level (i.e. class, struct or interface) implicitly means “internal”
Practical use-case: if you’re building a .NET assembly that is intended to be an SDK to a third party, but you need helper types and methods within your assembly that you don’t want to expose to the outside world, the use of the “internal” access modifier is justified.
 
Note that if your SDK spans multiple assemblies that need access to each others’ internal types and methods, use the InternalsVisibleTo assembly-level attribute.
 
Now that the record’s straight, here’s a couple of recipes you can accomplish with the “internal” access modifier beyond simple hiding of types/methods:
 
Problem
You want to provide a set of public classes that derive from a public base class, but you want to disallow people external to your assembly from deriving their own classes from the base class…OR, you want a class publically available but you want to disallow external components from instantiating the class directly (presumably because you want to provide a factory method that does something non-trivial).
Solution
Define an internal constructor.
Example
public class Foo
{
internal Foo()
{
}
}

// Deriving from Foo can be done within the assembly.
// Will result in a build failure outside of the assembly
public class Bar : Foo
{
}

// Can be instantiated within the assembly
// Will result in a build failure outside of the assembly
Foo foo = new Foo();

// Works both internal and external to the assembly
Bar bar = new Bar();


Problem

You want to define an interface that you want to restrict to code within your assembly, but want a public class that implements that interface while hiding its implementation.

Solution

Define an internal interface and have classes implement the interface explicitly.

Example
internal interface IFoo
{
string Message { get; }
}

public class Bar : IFoo
{
// Explicit interface implementation
string IFoo.Message
{
get
{
return "For your eyes only";
}
}
}

// Can be instantiated internal and external to the assembly
Bar bar = new Bar();

// Will result in a build failure both internal and external to the assembly
Console.WriteLine(bar.Message);

// Works only internal to the assembly
// Will result in a build failure outside of the assembly
IFoo foo = (IFoo)bar;
Console.WriteLine(foo.Message);

No comments:

Post a Comment