4 Ways To Emulate The Friend Keyword Of C++ In C#

Posted by : on

Category : C#

Introduction

Sometimes we may find the need in C# to create functionality that resembles the functionality of a friend class in C++. This can happen when we need for a class to have access to members of another class that are not public.

Generally the friend keyword in C++ is a dangerous choice, as it breaks encapsulation. Any change to a private member should not affect any other class of the program as this can create hard to find bugs. There are cases though, that we may need accessibility to some members of our class from only one or two other classes. Making these members public is too public, as we don’t want these members to be exposed to other classes, but making them private is too private because the classes that need them, cannot access them.

Let’s suppose that we have the following code:

public class Enemy
{
      public void Move(int speed) => Console.WriteLine($"Moving with speed: {speed}");
      public void Attack(int damage) => Console.WriteLine($"Doing {damage} damage.");
}

public class Goblin 
{
   private readonly Enemy _enemy;
   private readonly int _speed = 10;
   private readonly int _damage = 100;

   public Goblin() => _enemy = new Enemy();

   public void Move()
   {
      Console.WriteLine("A goblin is Moving...");
      _enemy.Move(_speed);
      Console.WriteLine("The goblin has finished attacking.");
   }

   public void Attack()
   {
      Console.WriteLine("A goblin is Attacking...");
      _enemy.Attack(_damage);
      Console.WriteLine("The goblin has finished moving");
   }
}

public class Orc 
{
   private readonly Enemy _enemy;
   private readonly int _speed = 5;
   private readonly int _damage = 200;

   public Orc() => _enemy = new Enemy();

   public void Move()
   {
      Console.WriteLine("An Orc is Moving...");
      _enemy.Move(_speed);
      Console.WriteLine("The Orc has finished attacking.");
   }

   public void Attack()
   {
      Console.WriteLine("An Orc is Attacking...");
      _enemy.Attack(_damage);
      Console.WriteLine("The Orc has finished moving");
   }
}

This works fine, but the Move and Attack are public. We don’t want these methods to be used by any other class other than the Orc and Goblin classes. If we had used inheritance, we could write these methods so they could only be accessed from child classes of the Enemy class, but now public is our only option.

Below, I have written four ways I have found, that can solve this problem to a certain degree. None of them provides 100% the same functionality with the friend keyword of C++. Each has its pros and cons and for that reason each one, depends on the situation.

Create an assembly of the relevant classes

The internal access modifier, allows members and types to be accessed only from classes that exist in the same assembly.

For the previous example our enemy class would be written like this:

public class Enemy
{
      internal void Move(int speed) => Console.WriteLine($"Moving with speed: {speed}");
      internal void Attack(int damage) => Console.WriteLine($"Doing {damage} damage.");
}

This doesn’t completely solve the problem. The Move and Attack methods are now accessible from all the classes that exist in the same assembly. That means that our assembly should only have these three classes.

Creating many assemblies, each with 3-4 classes, eventually will become cumbersome. We would end up with a project that has many small class libraries, that their only common thing would be the emulation of the friend keyword. A library, especially in a framework, is better to contain classes that provide a complex functionality and for that reason assemblies are better suited for creating higher level structures than this.

Nested classes

We can have the “friends” of the Enemy class as nested classes inside. Nested classes have access to the private parts of the class that contains them. Here’s the code:

public class Enemy
{
      private void Move(int speed) => Console.WriteLine($"Moving with speed: {speed}");
      private void Attack(int damage) => Console.WriteLine($"Doing {damage} damage.");
      
      public class Goblin 
      {
         private readonly Enemy _enemy;
         private readonly int _speed = 10;
         private readonly int _damage = 100;

         public Goblin() => _enemy = new Enemy();

         public void Move()
         {
            Console.WriteLine("A goblin is Moving...");
            _enemy.Move(_speed);
            Console.WriteLine("The goblin has finished attacking.");
         }

         public void Attack()
         {
            Console.WriteLine("A goblin is Attacking...");
            _enemy.Attack(_damage);
            Console.WriteLine("The goblin has finished moving");
         }
      }
      
      public class Orc 
      {
         private readonly Enemy _enemy;
         private readonly int _speed = 5;
         private readonly int _damage = 200;

         public Orc() => _enemy = new Enemy();

         public void Move()
         {
            Console.WriteLine("An Orc is Moving...");
            _enemy.Move(_speed);
            Console.WriteLine("The Orc has finished attacking.");
         }

         public void Attack()
         {
            Console.WriteLine("An Orc is Attacking...");
            _enemy.Attack(_damage);
            Console.WriteLine("The Orc has finished moving");
         }
      }
}

Now we can create Goblin and Orc objects like this:

Enemy.Goblin goblin = new();
Enemy.Orc orc = new();

But this solution is not ideal either. The reason is that now we can only have one-to-one, or one-to-many relationships, but not many-to-one or many-to-many relationships. If we wanted our Orc and Goblin classes to have access as friend classes to another class, for example a Character class, we cannot do it with nesting and the assembly solution would be our only choice.

Nested class in parent base class

Another way, is to create an abstract base class that contains our nested class and have the “friend” classes inherit from it. If we have many “friend” classes this will reduce the size of our class but add the cost of maintenance because now we have used inheritance on top of composition. The code now will look like this:

public abstract class BaseEnemy
{
   protected class Enemy
   {
      public void Move(int speed) => Console.WriteLine($"Moving with speed: {speed}");
      public void Attack(int damage) => Console.WriteLine($"Doing {damage} damage.");
   }  
}

public class Goblin : BaseEnemy
{
   private readonly Enemy _enemy;
   private readonly int _speed = 10;
   private readonly int _damage = 100;

   public Goblin() => _enemy = new Enemy();

   public void Move()
   {
      Console.WriteLine("A goblin is Moving...");
      _enemy.Move(_speed);
      Console.WriteLine("The goblin has finished attacking.");
   }

   public void Attack()
   {
      Console.WriteLine("A goblin is Attacking...");
      _enemy.Attack(_damage);
      Console.WriteLine("The goblin has finished moving");
   }
}
      
public class Orc : BaseEnemy
{
   private readonly Enemy _enemy;
   private readonly int _speed = 5;
   private readonly int _damage = 200;

   public Orc() => _enemy = new Enemy();

   public void Move()
   {
      Console.WriteLine("An Orc is Moving...");
      _enemy.Move(_speed);
      Console.WriteLine("The Orc has finished attacking.");
   }

   public void Attack()
   {
      Console.WriteLine("An Orc is Attacking...");
      _enemy.Attack(_damage);
      Console.WriteLine("The Orc has finished moving");
   }
}

There are some differences from the previous solution.

Now the methods of the Enemy class are public, but it doesn’t matter because the Enemy class is protected. We cannot anymore create objects of the Enemy class unless we inherit from BaseEnemy, so the public accessibility is not a problem.

We can now have more than one protected class in the base class. That means that our Orc and Goblin classes can be friends with more than one class.

We gain in encapsulation of the Enemy class and for that reason creating goblins and orcs is more straightforward:

Goblin goblin = new();
Orc orc = new();

but we make our code harder to maintain due to the inheritance.

Unfortunately with this way, our Enemy class is more of a helper class. Other classes cannot use it now, so if we want a class that can be used by other classes for its public behaviours and have some friend classes that can use its private behaviours, this way won’t do.

Nested class with default interface implementation

A variation of the above is using default interface implementation:

public interface IEnemy
{
   protected class Enemy
   {
      public void Move(int speed) => Console.WriteLine($"Moving with speed: {speed}");
      public void Attack(int damage) => Console.WriteLine($"Doing {damage} damage.");
   }
}

public class Goblin : IEnemy
{
   private readonly IEnemy.Enemy _enemy;
   private readonly int _speed = 10;
   private readonly int _damage = 100;

   public Goblin() => _enemy = new IEnemy.Enemy();

   public void Move()
   {
      Console.WriteLine("A goblin is Moving...");
      _enemy.Move(_speed);
      Console.WriteLine("The goblin has finished attacking.");
   }

   public void Attack()
   {
      Console.WriteLine("A goblin is Attacking...");
      _enemy.Attack(_damage);
      Console.WriteLine("The goblin has finished moving");
   }
}
      
public class Orc : IEnemy
{
   private readonly IEnemy.Enemy _enemy;
   private readonly int _speed = 5;
   private readonly int _damage = 200;

   public Orc() => _enemy = new IEnemy.Enemy();

   public void Move()
   {
      Console.WriteLine("An Orc is Moving...");
      _enemy.Move(_speed);
      Console.WriteLine("The Orc has finished attacking.");
   }

   public void Attack()
   {
      Console.WriteLine("An Orc is Attacking...");
      _enemy.Attack(_damage);
      Console.WriteLine("The Orc has finished moving");
   }
}

Now, we can have many interfaces with a different class each. That makes it easier to maintain if we want many-to-one or many-to-many relationships, but we still have the problem that these classes can only be used by their friends and are completely unaccessible from any class that doesn’t implement the interface, so no public access for some classes and private access for others.

Conclusion

I don’t really need the friend functionality of the C++ that often. In those rare times that I do need it, I can actually take some steps back and restructure my code. The friend behaviour of C++, actually breaks encapsulation and for that reason is very dangerous. A change in a private method or type should not affect the rest of the code. In any case, the methods described above can offer a limited emulation of that functionality.

Using the internal keyword and creating an assembly, is the easiest way to do it, but creates the danger of making our project too granular.

A nested class, is the next best approach, but with the danger of creating really big files and classes and the disadvantage that only one class can “befriend” others.

Using a base abstract class creates a “helper” class. A class that cannot be used by others, but only by its “friends”, the classes that derive from the base.

Finally with the default interface implementation, we can have the same functionality like using the inheritance from the base abstract class, but we can create many interfaces and mix and match the classes we want to be “friends”.

Thank you for reading, if you know any other way to emulate the behaviour of the friend keyword of C++, if you think I forgot something or if you have any questions or comments, you can use the comments section or contact me directly via the contact form or by email. Also if you don’t want to miss any of the new blog posts, you can always subscribe to my newsletter or the RSS feed.


Follow me: