Mastering C#: Unraveling the Concepts of C# & OOPS
C# Important Concepts- (Reflection and Attributes)
What is Reflection?
In C#, reflection allows us to inspect and manipulate classes, constructors, methods, and fields at run time. System.Reflection namespace is used to perform reflection.
C# Reflection Hierarchy
Applications of Reflection
Use Assembly to define and load assemblies, load modules that are listed in the assembly manifest, and locate a type from this assembly and create an instance of it.
Use Module to discover information such as the assembly that contains the module and the classes in the module. You can also get all global methods or other specific, non-global methods defined on the module.
Use ConstructorInfo to discover information such as the name, parameters, access modifiers (such as
public
orprivate
), and implementation details (such asabstract
orvirtual
) of a constructor. Use the GetConstructors or GetConstructor method of a Type to invoke a specific constructor.Use MethodInfo to discover information such as the name, return type, parameters, access modifiers (such as
public
orprivate
), and implementation details (such asabstract
orvirtual
) of a method. Use the GetMethods or GetMethod method of a Type to invoke a specific method.Use FieldInfo to discover information such as the name, access modifiers (such as
public
orprivate
) and implementation details (such asstatic
) of a field, and to get or set field values.Use EventInfo to discover information such as the name, event-handler data type, custom attributes, declaring type, and reflected type of an event, and to add or remove event handlers.
Use PropertyInfo to discover information such as the name, data type, declaring type, reflected type, and read-only or writable status of a property, and to get or set property values.
Use ParameterInfo to discover information such as a parameter's name, data type, whether a parameter is an input or output parameter, and the position of the parameter in a method signature.
Use CustomAttributeData to discover information about custom attributes when you are working in the reflection-only context of an application domain. CustomAttributeData allows you to examine attributes without creating instances of them. The classes of the System.Reflection.Emit namespace provide a specialized form of reflection that enables you to build types at run time.
Examples & Uses
One of the biggest implementations of Reflection is Visual Studio itself. Suppose, in visual studio, we create an object of the String class, and when we press obj. then visual studio intelligence shows all the properties, methods, fields, etc. of that object as shown in the below image. And this is possible because of the Reflection in C#.
This means, Reflection inspects the assembly and shows the metadata of that assembly. Now, I hope you understand the definition of Reflection. Now, let us proceed and understand how to implement reflection in C#.
So, now we are going to write a simple example implementing reflection in C# language. So, first, create a console application with the name ReflectionDemo. And to this ReflectionDemo solution, let us add a class library project with the name SomeClassLibrary. Once you add the Class Library Project, your solution should look like the following.
As you can see, the Class Library Project is created with a class called Class1.cs. Now, modify the Class1.cs class file as follows. As you can see, here we have created some private and public fields, some private and public properties, and some private and public methods.
using System;
namespace SomeClassLibrary
{
public class Class1
{
public int X;
private int Y;
public int P1 { get; set; }
private int P2 { get; set; }
public void Method1()
{
Console.WriteLine("Method1 Invoked");
}
private void Method2()
{
Console.WriteLine("Method2 Invoked");
}
}
}
Now, build the Class Library Project. And once you build the Class Library Project an assembly (with extension .DLL) will be generated inside the Project’s bin=> Debug location as shown in the below image.
So, in my machine, in the following location, the SomeClassLibrary.dll assembly is created. Copy the location. D:\Projects\ReflectionDemo\SomeClassLibrary\bin\Debug
Now, remove the Class Library Project from the solution. To do so, right-click on the Class Library Project and then click on the Remove option as shown in the below image.
Once you click on the Remove option, one popup will come simply click Yes to remove the project. Once you remove the Class Library Project, then your solution will contain only the ReflectionDemo Console Application as shown in the below image.
Browse the Properties, Methods, and Variables of SomeClassLibrary Assembly
Now, what we need to do is, we need to display the Properties, Methods, and Variables of the SomeClassLibrary assembly using Reflection. Implementing reflection is a three steps process. The steps are as follows.
Step1: Import the Reflection Namespace
Step2: Get the Type of the Object
Step3: Browse the Metadata of the Object
Sample Code:
using System;
//Step1: Import the Reflection namespace
using System.Reflection;
namespace ReflectionDemo
{
class Program
{
static void Main(string[] args)
{
//Browse the Properties, Methods, variables of SomeClassLibrary Assembly
//Step2: Get the Type
//Get the Assembly Reference
var MyAssembly = Assembly.LoadFile(@"D:\Projects\ReflectionDemo\SomeClassLibrary\bin\Debug\SomeClassLibrary.dll");
//Get the Class Reference
var MyType = MyAssembly.GetType("SomeClassLibrary.Class1");
//Create an instance of the type
dynamic MyObject = Activator.CreateInstance(MyType);
//Get the Type of the Instance
Type parameterType = MyObject.GetType();
//Step3: Browse the Metadata
//To Get all Public Fields/variables
Console.WriteLine("All Public Fields");
foreach (MemberInfo memberInfo in parameterType.GetFields())
{
Console.WriteLine(memberInfo.Name);
}
//To Get all Public Methods
Console.WriteLine("\nAll Public Methods");
foreach (MemberInfo memberInfo in parameterType.GetMethods())
{
Console.WriteLine(memberInfo.Name);
}
//To Get all Public Properties
Console.WriteLine("\nAll Public Properties");
foreach (MemberInfo memberInfo in parameterType.GetProperties())
{
Console.WriteLine(memberInfo.Name);
}
Console.ReadKey();
}
}
}
Output
Example to show Type Details using Reflection in C#:
Now, we want to show the class name, fully qualified class name, and namespace name. For this, we need to call the Name, FullName, and Namespace properties as shown in the below example.
using System;
using System.Reflection;
namespace ReflectionDemo
{
class Program
{
static void Main(string[] args)
{
//Get the Assembly Reference
var MyAssembly = Assembly.LoadFile(@"D:\Projects\ReflectionDemo\SomeClassLibrary\bin\Debug\SomeClassLibrary.dll");
//Get the Class Reference
var MyType = MyAssembly.GetType("SomeClassLibrary.Class1");
// Print the Type details
Console.WriteLine($"Full Name = {MyType.FullName}");
Console.WriteLine($"Just the Class Name = {MyType.Name}");
Console.WriteLine($"Just the Namespace Name = {MyType.Namespace}");
Console.ReadKey();
}
}
}
Output
Invoke Methods Dynamically Using Reflection?
One of the good features of reflection is it will inspect the metadata of an assembly and we already discussed this. Another good feature of using Reflection is that we can invoke the members of an assembly in C# using Reflection. So, if you remember we have defined one public method i.e. Method1 in our class library assembly and we want to invoke that method using reflection. To invoke the method of assembly using reflection, we need to use the InvokeMember method as shown in the below image.
using System;
//Step1: Import the Reflection namespace
using System.Reflection;
namespace ReflectionDemo
{
class Program
{
static void Main(string[] args)
{
//Browse the Properties, Methods, variables of SomeClassLibrary Assembly
//Step2: Get the type
//Get the Assembly Reference
var MyAssembly = Assembly.LoadFile(@"D:\Projects\ReflectionDemo\SomeClassLibrary\bin\Debug\SomeClassLibrary.dll");
//Get the Class Reference
var MyType = MyAssembly.GetType("SomeClassLibrary.Class1");
//Create an instance of the type
dynamic MyObject = Activator.CreateInstance(MyType);
//Get the Type of the class
Type parameterType = MyObject.GetType();
//Step3: Browse the Metadata
//To Get all Public Fields/variables
Console.WriteLine("All Public Members");
foreach (MemberInfo memberInfo in parameterType.GetMembers())
{
Console.WriteLine(memberInfo.Name);
}
Console.WriteLine("\nInvoking Method1");
parameterType.InvokeMember("Method1",
BindingFlags.Public |
BindingFlags.InvokeMethod |
BindingFlags.Instance,
null, MyObject, null
);
Console.ReadKey();
}
}
}
Output
Note: Reflection is used to find all types in an assembly and/or dynamically invoke methods in an assembly. This includes information about the type, properties, methods, and events of an object. With Reflection, we can dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties.
Thanks for your time. I hope this post was helpful and gave you a mental model for Reflection in C#!