21
NovIntroduction to Reflection in C#
Reflection in C#
Reflection in C# is important for developers who want to work with code dynamically, even when they don't know everything about it beforehand. It is like having the ability to inspect and interact with types, methods, and properties at runtime, giving you more control and flexibility. Reflection in C# allows you to work with objects and methods without knowing their full details at compile time, making your code more adaptable.In this C# tutorial, we will cover what reflection in C# is, the types of reflection, how to use attributes and reflection in C#, and provide examples to help you understand when and how to use reflection.
Read More: Top 50 C# Interview Questions & Answers To Get Hired |
What is Reflection in C#?
Reflection in C# is the ability to inspect and manipulate the structure of your program at runtime. With reflection, you can:
- Discover the types defined in assemblies (such as classes, interfaces, enums, etc.).
- Inspect the members of a type (methods, fields, properties, events, etc.).
- Create instances of types dynamically.
- Invoke methods or access properties without compile-time knowledge.
- Work with attributes applied to various code elements.
Why Use Reflection in C#?
Reflection is valuable when you want your program to be adaptable and dynamic. Here are some scenarios where you might use reflection:
- Framework Development: If you’re developing a framework or library, reflection allows you to find and use types, methods, and properties without knowing their specifics in advance.
- Working with Attributes: Attributes provide metadata about code elements, and reflection helps you access this metadata to modify the behavior of your application.
- Testing: Reflection is used in testing frameworks like NUnit and MSTest to discover and run test methods dynamically.
- Dynamic Type Creation: You can create objects at runtime, even if their type is unknown at compile time, which is useful when working with plugins or modules.
Is Reflection In C# Slow?
- Yes, reflection in C# can be slower compared to regular method calls.
- This is because it involves inspecting and interacting with types and members at runtime, which adds overhead.
- You might notice performance issues, especially in scenarios where reflection is used frequently or in tight loops.
- It's best to use reflection judiciously and only when necessary, as it can impact the overall performance of your application.
C# Reflection Hierarchy
- C# reflection hierarchy allows you to inspect and interact with the metadata of types, members, and assemblies at runtime.
- At the top level is the System.
- Reflection namespace contains classes like Assembly, Module, Type, and MemberInfo.
- Each of these classes provides specific functionality for examining assemblies, modules, types, and their members.
C# Type Class
The C# Type
class represents type declarations for classes, interfaces, enums, arrays, and value types. It's part of the System
namespace and inherits from the System.Reflection.MemberInfo
class. The Type
class is essential for working with reflection because it provides the methods and properties necessary to inspect and manipulate types.
C# Type Properties
Property | Description |
Assembly | Gets the Assembly in which the type is defined. |
AssemblyQualifiedName | Retrieves the fully qualified name of the type, including the assembly name. |
BaseType | Retrieves the base or parent type of the current type. |
FullName | Gets the fully qualified name of the type. |
IsAbstract | Check if the type is abstract. |
IsArray | Check if the type is an array. |
IsClass | Check if the type is a class. |
IsEnum | Check if the type is an enum. |
IsInterface | Check if the type is an interface. |
IsPublic | Check if the type is public. |
IsSealed | Check if the type is sealed (cannot be inherited). |
Name | Retrieves the simple name of the type. |
Namespace | Gets the namespace where the type is declared. |
C# Type Methods
Method | Description |
GetConstructors() | Retrieves all public constructors for the type. |
GetFields() | Retrieves all public fields for the type. |
GetMethods() | Retrieves all public methods for the type. |
GetProperties() | Retrieves all public properties for the type. |
GetType(String) | Retrieves the type by its name. |
InvokeMember() | Invokes a specific member of the type dynamically. |
Example 1: Get the Type of a Variable
using System;
public class ReflectionExample
{
public static void Main()
{
int number = 42;
Type type = number.GetType();
Console.WriteLine(type);
}
}
Output
System.Int32
Explanation
- In this example, we use
GetType()
to determine the type of the variablenumber
, which returnsSystem.Int32
, as expected.
Example 2: Inspect Methods of a Type
using System;
using System.Reflection;
public class ReflectionExample
{
public static void Main()
{
Type stringType = typeof(string);
MethodInfo[] methods = stringType.GetMethods();
Console.WriteLine("Methods of String type:");
foreach (var method in methods)
{
Console.WriteLine(method.Name);
}
}
}
Output
Methods of String type:
Clone
CompareTo
Contains
CopyTo
...
Explanation
- This code uses
GetMethods()
to retrieve all the methods of theString
class and prints their names. - Reflection makes it possible to access these methods dynamically at runtime.
Types of Reflection in C#
When working with reflection in C#, you generally deal with four main types:
- Assembly Reflection
- Type Reflection
- Member Reflection
- Attribute Reflection
1. Assembly Reflection
- Assembly reflection is the process of examining an assembly (a compiled .dll or .exe file) to discover its contents, such as classes, interfaces, enums, and methods.
- This is useful when you need to analyze or load assemblies dynamically.
using System;
using System.Reflection;
public class Program
{
public static void Main()
{
Assembly assembly = Assembly.GetExecutingAssembly();
Type[] types = assembly.GetTypes();
foreach (Type type in types)
{
Console.WriteLine(type.FullName);
}
}
}
Output
Program
System.Object
Explanation
- The code is used
Assembly.GetExecutingAssembly()
to get the assembly that is currently running. GetTypes()
retrieves all the types (like classes and interfaces) defined in that assembly.- A
foreach
loop goes through each type, and it prints the full name of the type usingConsole.WriteLine
. - The output shows two types:
Program
– the current class where the code is running.System.Object
– the base class for all C# classes.
2. Type Reflection
- Type reflection allows you to examine details about a specific type, such as its methods, fields, properties, and events.
- You can also create instances of a type or call its methods dynamically.
using System;
using System.Reflection;
public class Program
{
public static void Main()
{
Type type = typeof(string);
MethodInfo[] methods = type.GetMethods();
foreach (MethodInfo method in methods)
{
Console.WriteLine(method.Name);
}
}
}
Output
Clone
CompareTo
Contains
CopyTo
EndsWith
Equals
GetEnumerator
GetHashCode
GetType
IndexOf
Insert
Join
LastIndexOf
PadLeft
PadRight
Remove
Replace
Split
StartsWith
Substring
ToCharArray
ToLower
ToLowerInvariant
ToString
ToUpper
ToUpperInvariant
Trim
TrimEnd
TrimStart
Explanation
- The code gets the
Type
object for thestring
class usingtypeof(string)
. GetMethods()
retrieves all the methods available in thestring
class.- A
foreach
loop goes through each method and prints its name usingConsole.WriteLine
. - The output lists various methods of the
string
class, such as:Clone
CompareTo
Contains
IndexOf
ToString
Trim
3. Member Reflection
- Member reflection involves working with specific members (methods, fields, properties, etc.) of a type.
- You can access these members, modify their values, or invoke them at runtime.
using System;
using System.Reflection;
public class Person
{
public string Name { get; set; }
}
public class Program
{
public static void Main()
{
Type type = typeof(Person);
PropertyInfo property = type.GetProperty("Name");
Person person = new Person();
property.SetValue(person, "Shailesh");
Console.WriteLine(person.Name);
}
}
Output
Shailesh
Explanation
- The code defines a class
Person
with a propertyName
. - In the
Main
method, it usestypeof(Person)
to get theType
object for thePerson
class. GetProperty("Name")
retrieves theName
property from thePerson
class.- A new instance
Person
is created. SetValue()
is used to set the value of theName
property to "Shailesh".- Finally,
Console.WriteLine(person.Name)
prints the name, which is "Shailesh".
4. Attribute Reflection
- Attribute reflection lets you access and read attributes applied to various elements in your code, such as classes, methods, and properties.
- Attributes provide metadata, and reflection is often used to determine how code elements should behave based on this metadata.
using System;
using System.Reflection;
[AttributeUsage(AttributeTargets.Method)]
public class LogAttribute : Attribute { }
public class Logger
{
[Log]
public void DoWork()
{
Console.WriteLine("Doing work...");
}
}
public class Program
{
public static void Main()
{
MethodInfo method = typeof(Logger).GetMethod("DoWork");
if (method.GetCustomAttribute<LogAttribute>() != null)
{
Console.WriteLine("Log attribute is present on DoWork method.");
}
}
}
Output
Log attribute is present on DoWork method.
Explanation
- The code defines a custom attribute called
LogAttribute
that can be applied to methods using[AttributeUsage(AttributeTargets.Method)]
. - The class
Logger
has a methodDoWork()
that is decorated with the[Log]
attribute. - In the
Main
method,GetMethod("DoWork")
retrieves theDoWork
method from theLogger
class. GetCustomAttribute
checks if the() LogAttribute
is present in theDoWork
method.- If the attribute is found, the message
"Log attribute is present on DoWork method."
is printed to the console.
Reflection in C# with Example
- Let's look at a complete example to understand how reflection works in practice.
- We will create a simple program that loads an assembly, inspects its types, creates an instance of a class, and calls its methods, all using reflection.
using System;
using System.Reflection;
public class Calculator
{
public int Add(int a, int b)
{
return a + b;
}
public int Subtract(int a, int b)
{
return a - b;
}
}
public class Program
{
public static void Main()
{
// Load the assembly
Assembly assembly = Assembly.GetExecutingAssembly();
// Get the Calculator type
Type calculatorType = assembly.GetType("Calculator");
// Create an instance of Calculator
object calculatorInstance = Activator.CreateInstance(calculatorType);
// Get the Add method
MethodInfo addMethod = calculatorType.GetMethod("Add");
// Invoke the Add method
object result = addMethod.Invoke(calculatorInstance, new object[] { 5, 3 });
Console.WriteLine($"Add Method Result: {result}");
}
}
Output
Add Method Result: 8
Explanation
- The
Calculator
class has two methods:Add
andSubtract
. In this code, we're focusing on theAdd
method. - The assembly is loaded using
Assembly.GetExecutingAssembly()
, which refers to the current running code. GetType("Calculator")
retrieves theCalculator
class type from the assembly.- An instance of the
Calculator
class is created usingActivator.CreateInstance()
, which lets you create an object dynamically at runtime. GetMethod("Add")
retrieves theAdd
method from theCalculator
class.- The
Invoke()
method calls theAdd
method on the instance of theCalculator
, passing in two numbers:5
and3
. - The result of the addition is printed to the console, which is
8
.
A Simple Use Case of C# Reflection
In this section, let's explore a simple yet powerful use case of C# Reflection and how you can utilize it in your projects. C# reflection allows you to dynamically inspect and manipulate types at runtime, which can be extremely useful when you don't have complete compile-time information about the code you’re working with.
Imagine you're working on a plugin-based system where different modules can be added or removed at runtime. You may not know the exact methods or properties of the classes until the program runs. Here, C# Reflection comes to the rescue by letting you inspect and interact with classes, methods, and properties dynamically.
Let's elaborate on this with an example:
using System;
using System.Reflection;
public class Calculator
{
public int Add(int a, int b)
{
return a + b;
}
public int Subtract(int a, int b)
{
return a - b;
}
}
public class Program
{
public static void Main()
{
// Load the assembly (the current one)
Assembly assembly = Assembly.GetExecutingAssembly();
// Get the Calculator type
Type calculatorType = assembly.GetType("Calculator");
// Create an instance of the Calculator class dynamically
object calculatorInstance = Activator.CreateInstance(calculatorType);
// Get the Add method from the Calculator class
MethodInfo addMethod = calculatorType.GetMethod("Add");
// Invoke the Add method dynamically
object result = addMethod.Invoke(calculatorInstance, new object[] { 5, 3 });
Console.WriteLine("Add Method Result: " + result);
}
}
Output
Add Method Result: 8
Explanation
- This code demonstrates the power of reflection by loading an assembly and interacting with a class dynamically.
- We first load the current assembly using
Assembly.GetExecutingAssembly()
. - Then, we retrieve the
Calculator
class type usingassembly.GetType("Calculator")
. - Using reflection, we create an instance of the
Calculator
class at runtime. - We fetch the
Add
method usingcalculatorType.GetMethod("Add")
and invoke it with arguments 5 and 3, receiving the result 8.
When to Use Reflection in C#
You should use reflection in C# when you need flexibility and dynamic behavior. Common use cases include:
- Plugin or Module Loading: Load and interact with classes and methods from external assemblies or modules.
- Testing Frameworks: Discover and execute test methods dynamically based on attributes or naming conventions.
- Serialization and Deserialization: Inspect and manipulate object properties to convert them to and from different formats.
- Frameworks and Libraries: Build reusable components that interact with unknown types and members dynamically.
Summary
FAQs
Take our Csharp skill challenge to evaluate yourself!
In less than 5 minutes, with our skill challenge, you can identify your knowledge gaps and strengths in a given skill.