Is the C# internal keyword a code smell?
Tags: csharp, codequality, programming, oop
Published: 2020-09-04 07:36:41

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/lcsrduu0ccfy3ginppkf.jpg)
<figcaption>
<a href='https://www.freepik.com/photos/background'>Background photo created by freepik - www.freepik.com</a>
</figcaption>

In this post, I am going to show why I think the internal keyword, when put on class members, is a code smell and suggest better alternatives.

## What is the internal keyword?

In C# the [internal keyword](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/internal%29) can be used on a class or its members. It is one of the C# [access modifiers](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/access-modifiers). Internal types or members are accessible **only within files in the same assembly**.

## Why we need the internal keyword?

“A common use of internal access is in component-based development because it **enables a group of components to cooperate in a private manner without being exposed to the rest of the application code**. For example, a framework for building graphical user interfaces could provide Control and Form classes that cooperate by using members with internal access. Since these members are internal, they are not exposed to code that is using the framework.” ([C# internal keyword documentation](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/internal))

These are the use cases I saw for using the internal keyword on a class member:

* Call a class’s private function within the same assembly.

* In order to test a private function, you can mark it as internal and exposed the dll to the test DLL via [InternalsVisibleTo](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.internalsvisibletoattribute?view=netframework-4.8).

Both cases can be viewed as a [code smell,](https://enterprisecraftsmanship.com/2017/10/23/unit-testing-private-methods/) saying that this private function should be public.

## Let's see some examples

Here is a simple example. a function in one class wants to access a private function of another class.

{% gist https://gist.github.com/limonana/f14023fd4ba0cd5c9f988db33ff60b4f %} 
The solution is simple — just mark A::func2 as public.

Let's look at a bit more complex example:

{% gist https://gist.github.com/limonana/cca11345370df773aad35c8c7dcc6491 %} 

What’s the problem? just mark func2 as public as we did before.

{% gist https://gist.github.com/limonana/9190b500feebf908659064d7124aa0f3 %} 

But we can’t 😞. B is an internal class so it cannot be part of the signature of a public function of a public class.

Those are the solutions I found, ordered by easiness:
1. Mark the function with the internal keyword
{% gist https://gist.github.com/limonana/295e8bed2b3586ed2fca74f221cf680b %}

2. Create an internal interface
{% gist https://gist.github.com/limonana/d784a2405be37480fbb28d0ae0683388 %} 

3. Extract A.func2 to another internal class and use it instead of A.func2.
{% gist https://gist.github.com/limonana/4347d0e9a666f8b674c4b58a6f27990c %} 

4. Decouple the function from internal classes and make it public. This is much dependant on what the function is doing with its inputs. decouple the internal classes can be very easy, very hard, and even impossible (without ruing the design).

### But we don’t have public classes we use interfaces…

Let's look at some more real-world example:

{% gist https://gist.github.com/limonana/6541fbf2e688ee5300b04b4199f032d3 %} 

Let's see how the previous solutions are adapted to this example:

1. Mark function with Internal. this means you will need to cast to class in order to call the function so *This will work only if class A is the only one that implements the interface*, meaning IA is not mocked in tests and there isn’t another production class that implements IA.
{% gist https://gist.github.com/limonana/bd8bc540f1ce812e2f1886e3a663488d %}

2. Create an internal interface that extends the public interface.
{% gist https://gist.github.com/limonana/9c32dd3ed4659b84f58cbfcec9b8b56e %}

3. Extract A.func2 to another internal class and use it instead of A.func2.

4. Decouple the function from internal classes and add it to the public interface.

We can see that the **internal keyword is the easiest solution**, but there are other solutions using the **traditional building blocks of OOP: classes and interfaces**. We can see that the 2nd solution — adding an internal interface is not much harder than marking the function with the internal keyword.

## Why not use the internal keyword?

As I showed in the previous examples, using the **internal keyword is the easiest solution**. But you are going to have a hard time in the future if you will need to:

* Move the public class A to another DLL (since the internal keyword will no longer apply to the same dll)

* Create another production class that implements IA

* Mock IA in tests

You may think “But this is just one line of code, I or anyone else can change it easily if needed”. **Now** you have **one** line of code that looks like that:

    ((MyClass)a).internalFunction

but if others will need to call this function too this **line will be copy-pasted around** inside the DLL.

## My Conclusion

I think marking a class member with the internal keyword **is a code smell**. In the examples I showed above it is the **easiest** solution, BUT can cause problems in the future. Creating an **internal interface is almost as easy and more explicit.**

## Compare to C++

The C++ “friend” keyword is similar to the C# internal keyword. It allows a class or a function to access private members of a class. The difference is it allows access to **specific** class or function and **not all the classes in the same DLL**. In my opinion, this is a better solution than the C# internal keyword.

## Further Reading
 - [Practical uses for the "internal" keyword in C#](https://stackoverflow.com/questions/165719/practical-uses-for-the-internal-keyword-in-c-sharp)
   
 - [Why does C# not provide the C++ style 'friend' keyword?](https://stackoverflow.com/questions/203616/why-does-c-sharp-not-provide-the-c-style-friend-keyword)