C# – Access modifiers

When you’re using a Queue class, you only need access to the Enqueue() and Dequeue() methods. Everything else is private. You don’t need to know how data is stored or managed internally. That’s encapsulation, and it’s enabled by access modifiers.

Access modifiers are used to hide members from other code. In C#, there are four main access modifiers: public, private, protected, and internal. They can be defined based on what they allow access to:

Access modifierWhat can access it
privateOnly the class
protectedOnly the class + its subclasses
internal (this is the default)Everything in the assembly

Access modifiers are enforced at compile time. IntelliSense will only show class members that are accessible. When you try to use a class member that is not accessible, you’ll get the “CS0122 <member name> is inaccessible due to its protection level” compiler error.

Sometimes you’ll find that you need to bypass access modifiers, such as when you want to unit test non-public methods. You can do that using reflection, as I’ll show below.

In this article, I’ll go into more details about access modifiers, how they affect unit testing, and how to use reflection to get access to any method.

Internal vs protected

The public and private access modifiers are relatively simple. Public means everything can access the class member. Private means only the class can access it.

The internal and protected access modifiers are a little more complicated. Internal means everything in the assembly can access the class member. Protected means only the class and its subclasses can access it.

You’d use protected when you want a class member to be accessible only to that class’s hierarchy. The following diagram illustrates how the protected access modifier works.

Diagram showing how the protected access modifier allows access from the class and subclass

The protected access modifier makes the MakeSound() method accessible to the Bird class and its subclasses. It’s accessible to Cardinal and Chickadee because they are subclasses of Bird. It’s inaccessible to the BirdFood and BirdWatcher classes because they aren’t subclasses of Bird.

You’d use internal if you only want the assembly to have access. The following diagram shows how the internal access modifier works.

Diagram showing how the internal access modifier only allows access from the assembly

The internal access modifier makes the MakeSound() method only accessible to the classes in the Bird assembly. That’s why the Cardinal and BirdFood classes both have access to it, and the classes in the BirdWatcher assembly don’t have access to it.

How access modifiers affect unit testing

You only need to unit test the public API of a class. The public API includes all public methods and excludes all private and protected methods. First, unit tests don’t have access to the private / protected methods. Second, the public methods should be using the private / protected methods internally, which means they are actually covered by the unit tests.

Internal methods are another story. Technically they aren’t part of the public API since they are only accessible to the assembly. But that’s not always true. You can make the internals accessible to other assemblies. Arguments can be made on both sides about whether you should unit test internal methods or not. There’s no right answer. Use your best judgment to determine if it makes sense to unit test your internal methods.

Use InternalsVisibleToAttribute to unit test internal methods

When you want to unit test your internal methods, you’ll need to make them accessible to the unit test project by using InternalsVisibleToAttribute.

Let’s say you have an assembly called Birds.dll and it has internal methods that you want to test. Your unit test assembly is called BirdTests.dll. In order to unit test the internal methods, you’d need to put the following in the Birds project:

using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("BirdTests")]
Code language: C# (cs)

Now the BirdTests unit test project can access the internal methods and you can unit test them.

Reflection gives you access to everything

In the previous section, I showed how to use InternalsVisibleToAttribute to be able to unit test internal methods. How about if you wanted to test private / protected methods? You can use reflection to get access to all methods in a class, no matter what access modifiers they are using. You can get internal, protected, and private methods this way.

I’ll show a few examples below.

Example: Use reflection to get internal and protected methods

Let’s say you have the following class definitions and you want to test the internal and protected methods:

public abstract class Bird { internal string MakeSound() { return ""; } protected void Fly() { } } public class Cardinal : Bird { }
Code language: C# (cs)

Here’s how to call the internal method using reflection:

var cardinal = new Cardinal(); var makeSoundMethod = cardinal.GetType().GetMethod("MakeSound", BindingFlags.Instance | BindingFlags.NonPublic); makeSoundMethod.Invoke(cardinal, null);
Code language: C# (cs)

This calls the internal MakeSound() method.

It’s the same approach for protected methods:

var cardinal = new Cardinal(); var flyMethod = cardinal.GetType().GetMethod("Fly", BindingFlags.Instance | BindingFlags.NonPublic); flyMethod.Invoke(cardinal, null);
Code language: C# (cs)

This calls the protected Fly() method.

Example: Use reflection to get a private method

When you’re trying to get a private method, you have to use reflection on the type that contains the private method declaration.

For example, let’s say you have the following two classes. The abstract Bird class has a private method, and the Cardinal class has a private method.

public abstract class Bird { private void Land() { } } public class Cardinal : Bird { private void Eat() { } }
Code language: C# (cs)

To get the private method declared in the abstract Bird class, you need to call GetMethod() on the Bird type instead of the Cardinal type.

var cardinal = new Cardinal(); var landMethod = cardinal.GetType().BaseType.GetMethod("Land", BindingFlags.Instance | BindingFlags.NonPublic); landMethod.Invoke(cardinal, null);
Code language: C# (cs)

Note: typeof(Bird).GetMethod(…) is equivalent to cardinal.GetType().BaseType.GetMethod(…) and is slightly less verbose, but also requires you to know the concrete type ahead of time.

Now to get the private method declared in the Cardinal class, you would need to use reflection on the Cardinal type, like this:

var cardinal = new Cardinal(); var eatMethod = cardinal.GetType().GetMethod("Eat", BindingFlags.Instance | BindingFlags.NonPublic); eatMethod.Invoke(cardinal, null);
Code language: C# (cs)

This calls the private Eat() method.

Leave a Comment