Friend Class Equivalent in C#
This tutorial will teach you about friend class equivalents in C#. First, we will discuss friend class and its usage in programming with C++ examples.
Next, in the absence of a friend class equivalent in C#, we’ll see the alternatives.
Friend Class in C++
An important programming feature mainly applied in object-oriented programming is data hiding. Keeping data members hidden from outside the class means that the data members can be updated within the class only.
Therefore, we can say that only one class (holding data members) can change the value of data members.
By hiding data, we reduce the testing scope because we must test the class we are modifying. No other class can access the private data members of some class; therefore, there is no need to test them if their code is not modified.
Sometimes, data hiding gets a little compromised in lengthy and complex codes. A class can declare some functions or classes as friends.
In response, the friend
functions and friend
classes can access the private data members.
The syntax of friendship is below.
class ABC {
... friend class XYZ;
friend int change_data_member(int, char);
...
Class ABC
declares class XYZ
as a friend in line#3. Line#4 shows the syntax for declaring a friend
method.
Here, class ABC
declares the change_data_member
method as a friend
function.
After receiving the friendship flag from class ABC
, every function of class XYZ
can access the private data members of class ABC
.
However, in case of granting friendship to a function has a limited scope of friendship. Only the friend
function (i.e., declared as a friend
) can access the private data of members of the friendship-granting class.
Let’s see the implementation of the friendship concept in C++.
#include <iostream>
using namespace std;
class ABC {
int privateMember;
public:
ABC(int privateMember) { this->privateMember = privateMember; }
friend int getPrivateMember(ABC &);
friend void setPrivateMember(ABC &, int);
};
int getPrivateMember(ABC &obj) { return obj.privateMember; }
void setPrivateMember(ABC &obj, int privateMember) {
obj.privateMember = privateMember;
}
int main() {
ABC abc(5);
cout << "Private Member: " << getPrivateMember(abc) << '\n';
setPrivateMember(abc, 7);
cout << "Private Member: " << getPrivateMember(abc) << '\n';
return 0;
}
In this code, class ABC
has private data member privateMember
. In the last two lines of the class body, friendship is granted to two non-class functions: getPrivateMember
and setPrivateMember
.
The output of this code is below.
Private Member: 5
Private Member: 7
The private data member is accessed for both input and output. Following is an example of a friend
class:
#include <iostream>
using namespace std;
class ABC {
int privateMember;
friend class DEF;
};
class DEF {
ABC abc;
public:
int getPrivateMember() { return abc.privateMember; }
void setPrivateMember(int privateMember) {
abc.privateMember = privateMember;
}
};
int main() {
DEF def;
def.setPrivateMember(12);
cout << "Private Member: " << def.getPrivateMember() << '\n';
return 0;
}
In the second line of class ABC
, friendship is granted to class DEF
. Having friendship status, the getPrivateMember
and the setPrivateMember
methods of the class DEF
can access the private members of class ABC
.
The output of this code is below.
Private Member: 12
This friend
function or friend
class concept is available in C++, not C#. However, there are some methods through which we can access non-member data functions.
Use C# Equivalent of Friend Class
There are different methods to access data members of any class from some non-member functions in C#. Let’s discuss this one by one.
Using Nested Classes
The closest C# equivalent/alternative of a C++ friend
class is creating a nested/inner class. A nested class can access the private data members of an outer class.
The following example creates the Inner_class
class as a nested class to Outer_class
. Being inside the scope of a containing class, the Inner_class
can access private members of the Outer_class
, thereby imitating the friend
class.
using System;
public class Outer_class {
int privateMember;
Outer_class(int privateMember) {
this.privateMember = privateMember;
}
public class Inner_class {
public void innerClassFunction() {
Outer_class obj = new Outer_class(5);
Console.WriteLine("Private Member: " + obj.privateMember);
}
}
}
public class Driver {
static public void Main() {
Outer_class.Inner_class obj = new Outer_class.Inner_class();
obj.innerClassFunction();
}
}
In the above code, we have one outer class and one inner class. The variable privateMember
is a private member of the outer class.
Inside the Inner_class
, we are accessing the private data member that is privateMember
of the outer class.
Next, we have the Driver
class, where we have created an object of the Inner_class
. Using the Inner_class
object, we call the innerClassFunction
inside the Inner_class
.
Output:
Private Member: 5
Though the above code builds and executes without issues, still, it is preferred to put the Inner_class
separate from the Outer_class
by using the partial class concept as given in the below example.
using System;
public partial class Outer_class {
int privateMember;
Outer_class(int privateMember) {
this.privateMember = privateMember;
}
}
public partial class Outer_class {
public class Inner_class {
public void innerClassFunction() {
Outer_class obj = new Outer_class(5);
Console.WriteLine("Private Member: " + obj.privateMember);
}
}
}
public class Driver {
static public void Main() {
Outer_class.Inner_class obj = new Outer_class.Inner_class();
obj.innerClassFunction();
}
}
In the second partial class definition of Outer_class
, we have a function innerClassFunction
. This innerClassFunction
method creates an object of the outer class.
We pass 5
as an argument for the constructor parameter while creating an Outer_class
object. This constructor parameter becomes the value of the data member in the first partial definition of the outer class, as seen in the output below.
Private Member: 5
Partial classes are important in large projects where multiple persons write different portions of a class.
Here, we are exploiting this partial class option and writing Inner_class
inside as another partial portion of the outer class. This partial scheme can keep the partial units separate, yet we can use those as a single unit.
The main advantage of this scheme is that the actual class definition is not exposed to the one who writes the Inner_class
definition.
Reflection Objects
Using the objects of Reflection
, we can get run-time type information.
We can use Reflection
objects to get the Type
information during the program execution. The System.Reflection
namespace can be used to access the metadata of a program in execution.
The System.Reflection
provides useful information at run-time and helps add different types, values, and class objects to the program.
Moreover, we can get a handle on the methods using the System.Reflection
namespace and test the class’s private methods.
In this way, we can invoke private methods of the class. Therefore, it can replicate the friend
class.
For example, assume the following class with a private method callable_fun()
.
public class Class1 {
private char callable_fun() {
return 'C';
}
}
To test the private function callable_fun
, we need to write the following code:
using System.Reflection;
public class Driver {
static public void Main() {
Class1 c = new Class1();
Type class1Type = c.GetType();
MethodInfo callMeMethod =
class1Type.GetMethod("callable_fun", BindingFlags.Instance | BindingFlags.NonPublic);
char result = (char)callMeMethod.Invoke(c, null);
Console.WriteLine("Output:" + result);
}
}
The output of this code is below.
Output:C
If you are using the Visual Studio Team System, in that case, you can get VS to automatically generate a proxy class with private accessors by right-clicking the method and selecting Create Unit Tests...
.
Using the InternalsVisibleToAttribute
Class
This class helps to enhance visibility to a specified assembly for those types usually visible within the current assembly only.
// Syntax
[System.AttributeUsage(System.AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)]
public sealed class InternalsVisibleToAttribute : Attribute
If we have two unsigned assemblies, then the InternalsVisibleToAttribute
class helps to access the private member of one unsigned assembly by another unsigned assembly. The name of one assembly (having the name of the friend
class/assembly) is passed as an argument.
Next, let’s look at an example where InternalsVisibleToAttribute
is used to access the private member of another unsigned assembly. Here, SecondClass
accesses the private member of FirstClass
.
See the below code.
using System;
using System.Runtime.CompilerServices;
using Utilities.Example;
[assembly:InternalsVisibleToAttribute("FirstClass")]
namespace Utilities.Example {
public class FirstClass {
internal static int InnerMethod(int x) {
return x * x;
}
}
}
The following example provides the source code for the SecondClass
assembly:
public class SecondClass {
public static void Main() {
Console.WriteLine(FirstClass.InnerMethod(10));
}
}
The output of this code is 100
.
If we have signed assemblies, then directory path and file name extension are not required.
The next example uses the InternalsVisibleToAttribute
to call the private method named innerMethod
in a signed assembly visible to another signed assembly. It defines the FirstClass
class that includes an internal innerMethod
method.
using System;
using System.IO;
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo(
"Friend_Assembly, PublicKey=002400000480000094" + "0000000602000000240000525341310004000" +
"001000100bf8c25fcd44838d87e245ab35bf7" + "3ba2615707feea295709559b3de903fb95a93" +
"3d2729967c3184a97d7b84c7547cd87e435b5" + "6bdf8621bcb62b59c00c88bd83aa62c4fcdd4" +
"712da72eec2533dc00f8529c3a0bbb4103282" + "f0d894d5f34e9f0103c473dce9f4b457a5dee" +
"fd8f920d8681ed6dfcb0a81e96bd9b176525a" + "26e0b3")]
public class FirstClass {
internal static int innerMethod(int x) {
return x * x;
}
}
Suppose the following example is compiled into a strong-named assembly named Friend_Assembly
. The inner method in FirstClass
will successfully call the innerMethod
, although the method is internal to the FirstClass
.
public class SecondClass {
public static void Main() {
int result = FirstClass.innerMethod(10);
Console.WriteLine(result);
}
}
The output of this code is, again, 100
.
We have presented different equivalents of the C++ friend
class in C#. Readers can use any as per their requirements.