I wanted to go over the visibility modifiers in C#. There are a few, it's not as simple as just public or private. Let's go through some scenarios and get our heads around what we can use, when and why.

I couldn't think of a good term to group the concepts of methods, constructors, and classes, so I will refer to these as 'things' for the duration of this post.

'public'

This is pretty easy. It's public. Anyone can find it and use it if they have your assembly to link to. This can be used on fields, properties, constructors, methods, classes, whether they are static things or instance things.

public class Foo 
{
    public Foo()
    {
        ...
    }

    public int num;
    public string GetAFoo() { ... }
    public static double FourtyTwo = 42.0;
    public static string GetABar() { ... }
}

public static class Baz
{
    ...
}

probably not worth spending a bunch of time on this. Onto the next one.

'private'

The private modifier is also not complicated. The access is restricted to the private scope of the class that holds it.

public class Foo
{
    private int _num;
    private string GetAFoo() { ... }
    private static double _fourtyTwo = 42.0;
    private static string GetABar() { ... }

    private class Bar 
    {
        ...
    }

    private static class Baz
    {

    }
}

Any methods inside the scope of Foo have access to use any of the things marked as private.

This has the effect that if you were to derive from this class, you couldn't access those things that have a private scope.

public class Derived : Foo 
{
    public void DoStuff()
    {
        //This method could not make use of _num, GetAFoo, _fourtyTwo, GetABar
        //or the classes Bar or Baz
    }
}

The default for most things is private. If you don't declare a modifier, this is most likely what you get. Personally, I never rely on defaults, and always explicitly write private against anything in the code I write. The only exception to this is non-nested classes, which I'll cover in the internal section.

Note that although classes cannot be private, they can if they are nested inside other classes. More on nested classes later on.

'protected'

The protected scope can be used in practically all the same places as we use private.

public class Foo
{
    protected int Num;
    protected string GetAFoo() { ... }
    protected static double FourtyTwo = 42.0;
    protected static string GetABar() { ... }

    protected class Bar 
    {
        ...
    }

    protected static class Baz
    {

    }
}

The key difference here is that they do become visible to the derived classes.

public void DoStuff()
{
    //This method can use Num, GetAFoo, FourtyTwo, GetABar
    //and the classes Bar and Baz
}

And like private, no one outside of the scope of the class or it's derived classes can access these things.

'internal'

The internal modifier, sits somewhere just below public. It basically says public to all code inside the same assembly. But consider it not available to be directly referenced from outside.

public class Foo 
{
    internal Foo()
    {
    ...
    }

    internal int num;
    internal string GetAFoo() { ... }
    internal static double FourtyTwo = 42.0;
    internal static string GetABar() { ... }
}

internal class Fizz
{
    ...
}
    
internal static class Buzz
{
    ...
}

Unlike private and protected, we can use internal on non-nested classes. In fact, without a visibility modifier, this is the default of these classes.

There is one feature forced on you when you make a class internal, however. You must not allow any public class to expose that other type. This means that a public property, method, or field cannot use the Type as the property or field type, or as a parameter, or return type of a method.

InternalsVisibleTo

Now I said that internal means you cannot reference the internal thing from outside the assembly. I am now going to show you how to allow someone to access these from outside the assembly.

Introducing InternalsVisibleToAttribute! This attribute can be used to name an assembly that is allowed to access your internals.

[assembly:InternalsVisibleTo("Friend1a")]

Usually, you might find this in an AssemblyInfo.cs file. We are declaring that someone with an assembly name "Friend1a" has access to your internals as if they were public. This can also be used with signed assemblies if required.

Why would you use this? The only case I've seen that makes sense is testing. Your test assembly will probably want to have tests covering your internal classes with unit tests. This gives them access to do so, without opening up the class to be public. Keep your internal classes hidden from anyone using your assembly, if they should not be using them.

The 'new' Modifier

The new modifier is an interesting keyword. For clarity, I'm not talking about these two usages:

  • new object()
  • public class Foo<T> where T: new() { ... }

This usage is not one I recommend using, but from time to time, you get a hint that you are hiding a method and should use the new keyword. Let's look at a usage, and talk through the problem.

public class Foo
{
    public int GetNumber()
    {
        ...
    }
}
    
public class Bar : Foo
{
    public int GetNumber()
    {
        ...
    }
}

This generates a compiler warning. Basically, by adding new, we are getting rid of the compiler warning. But now someone reading the code can see that something is happening here, which they wouldn't easily see without the new keyword. There are two placements of the keyword, before or after the visibility modifier.

public class Bar : Foo
{
    new public int GetNumber()
    {
        ...
    }
}
    
public class Bar : Foo
{
    public new int GetNumber()
    {
        ...
    }
}

Usually, this warning is treated as an error and stops compilation. So why is this bad? Well, we basically have two versions of our value. One that belongs to Foo, and one that belongs to Bar, both with the same name. When you use that name from Bar, you are referring to the Bar version, when doing in regards to Foo, you mean the Foo version. This just gets damn confusing, and mistakes get made. Not to mention, as you cast back and forward, you toggle between which property gets used. Don't like it. Stop it now.

The correct solution, of course, is to use virtual and override. I'm not covering them in this post, but they let you have a single implementation for any instance, and no matter how you reference it, the correct one is used on the instance. Just do it.

Nested classes

I kind of touched on nested classes with visibility earlier. They can be public, private, protected or internal. That determines its visibility to external and derived classes as described above. Nested classes are private visibility by default. Cool.

Also, their internal things are scoped following the normal rules.

public class Foo
{
    public class Bar
    {
        public int Num;
        protected string GetAFoo() { ... }
            
        private class Baz
        {
            ...
        }
    }
    public void DoStuff()
    {
        var b = new Bar();
        var num = b.Num; //works, I can see and access public things
        //I can't use b.GetAFoo() because its protected.
        //I can't use  new Bar.Baz() because it's private.
    }
}

The fun starts here. We can access anything from inside the parent class while in the code belonging to the nested child. When inside the parent, we can see the parent's insides.

public class Foo
{
    public int Num;

    protected string GetAFoo() { ... }

    private class Baz
    {
        ...
    }

    public class Bar
    {
        public void DoStuff()
        {
            var f = new Foo();
            var num = f.Num; //works, I can see and access public things.
            f.GetAFoo(); // works, I can see and access Foo protected things.
            var b = new Baz(); // works, I can see his private things.
        } 
    }
}

This is the main benefit of being able to create and use nested classes. Breaking encapsulation.

Explicit interface implementation

The last story of visibility is this idea of explicit interface implementation. Let's use an example with a simple interface.

public interface IFooable
{
    int FooIt();
}

We can implement it normally like this:

public class Fighter : IFooable
{
    public int FooIt()
    {
        return 666;
    }
}

This is known as implicit implementation. When we talk about explicit interface implementation we mean this:

public class Dave : IFooable
{
    int IFooable.FooIt()
    {
        return 666;
    }
}

So what's the difference? It becomes clear when we use at the usage code:

var fighter = new Fighter();
fighter.FooIt();
IFooable castedFighter = (IFooable)fighter;
castedFighter.FooIt(); //The interface allows you to call this method

var dave = new Dave();
//dave.FooIt(); //This doesn't compile, the implementation is hidden
IFooable castedDave = (IFooable)dave;
castedDave.FooIt(); //The interface allows you to call this method

What this gives us is a way to hide the method from the class, but still allow it to meet the expectations of the interface. Why is this useful? If you have name collision on your interfaces or signature mismatches, you can use explicit implementations to implement all of the correct versions against the correct interface without the compiler yelling at you. You might decide to leave one implicit so you can use it on the object, or keep them all explicit.

Two common use cases are IDisposable (hide the Dispose() method unless you explicitly cast to IDisposable) and IList + IList<T>. This second one has many methods that only differ by the return type, so it's nice to hide the non-generic versions from the long list of interface methods available. You can see this by casting a List<int> to IList or to IEnumerable, and see how the IntelliSense shows you different methods on the two references.

Conclusion

So that's a bunch of stuff around visibility. I Hope that informed and entertained you. Drop me a line if you think I've missed anything that comes under the visibility umbrella.

Notes

I use a lot of ellipses in my code. This is just my way of saying more code goes here. It's not a special syntax feature that you haven't seen before, just my shorthand. :) And sorry for all the things. (Please suggest a term to me if a better one exists).