Introduction to Reflection in C#

Introduction to Reflection in C#

28 Oct 2024
Beginner
154 Views
27 min read
Learn with an interactive course and practical hands-on labs

Free C# Programming Certification Course: Learn C# for Beginners

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

Below is a diagram representing the C# reflection hierarchy:
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

    PropertyDescription
    AssemblyGets the Assembly in which the type is defined.
    AssemblyQualifiedNameRetrieves the fully qualified name of the type, including the assembly name.
    BaseTypeRetrieves the base or parent type of the current type.
    FullNameGets the fully qualified name of the type.
    IsAbstractCheck if the type is abstract.
    IsArrayCheck if the type is an array.
    IsClassCheck if the type is a class.
    IsEnumCheck if the type is an enum.
    IsInterfaceCheck if the type is an interface.
    IsPublicCheck if the type is public.
    IsSealedCheck if the type is sealed (cannot be inherited).
    NameRetrieves the simple name of the type.
    NamespaceGets the namespace where the type is declared.

    C# Type Methods

    MethodDescription
    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

    Now we will explore some examples using Csharp Type Property and Type Method
    
    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 variable number, which returns System.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 the String 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
    Each type serves a different purpose, as explained below.

    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 usedAssembly.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 using Console.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 the string class using typeof(string).
    • GetMethods() retrieves all the methods available in the string class.
    • A foreach loop goes through each method and prints its name using Console.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 property Name.
    • In the Main method, it uses typeof(Person) to get the Type object for the Person class.
    • GetProperty("Name") retrieves the Name property from the Person class.
    • A new instancePerson is created.
    • SetValue() is used to set the value of the Name 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 method DoWork() that is decorated with the [Log] attribute.
    • In the Main method, GetMethod("DoWork") retrieves the DoWork method from the Logger class.
    • GetCustomAttribute() checks if the LogAttribute is present in the DoWork 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 and Subtract. In this code, we're focusing on the Add method.
    • The assembly is loaded using Assembly.GetExecutingAssembly(), which refers to the current running code.
    • GetType("Calculator") retrieves the Calculator class type from the assembly.
    • An instance of the Calculator class is created using Activator.CreateInstance(), which lets you create an object dynamically at runtime.
    • GetMethod("Add") retrieves the Add method from the Calculator class.
    • The Invoke() method calls the Add method on the instance of the Calculator, passing in two numbers: 5 and 3.
    • 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 using assembly.GetType("Calculator").
    • Using reflection, we create an instance of the Calculator class at runtime.
    • We fetch the Add method using calculatorType.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
      Reflection in C# is a powerful tool that allows you to inspect and manipulate code at runtime. It enables you to discover and interact with assemblies, types, and their members, such as methods and properties, without knowing their details at compile time. Reflection is widely used in scenarios like framework development, testing, dynamic type creation, and working with attributes to make applications more adaptable and flexible.

      Boost your C# skills with ScholarHat's comprehensive C# Programming Course! Learn more about advanced concepts like Reflection, enhance your coding capabilities, and become a pro at creating dynamic applications. Join our course today and take the next step in your programming journey!

      FAQs

      You should use reflection in C# when you need to inspect or interact with an assembly's metadata, like accessing methods, properties, or types at runtime. It is useful for creating flexible, dynamic applications, such as object mapping or plugin-based systems.

      Instead of reflection in C#, you can use interfaces, delegates, or generics to achieve similar outcomes. These options provide more type safety and better performance when you need to access methods or properties dynamically.

      The Reflection API in C# is needed when you want to inspect and manipulate metadata at runtime. It lets you access information about assemblies, types, methods, and properties dynamically, which is useful for scenarios like building frameworks, object mapping, or creating plugins without knowing the details at compile time.

      Reflection allows for inspecting and interacting with the metadata of types, methods, properties, fields, and assemblies at runtime. It lets you dynamically create instances, invoke methods, and access or modify fields and properties, enabling flexible and adaptive programming, such as in serialization, dependency injection, or plugin-based architectures.

      The benefit of reflection in C# is that it provides flexibility by allowing you to inspect and interact with types, methods, and properties at runtime. It enables dynamic object creation, method invocation, and access to metadata, which is valuable for scenarios like building frameworks, implementing serialization, or developing plugin systems where types or members are unknown at compile time.

      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.

      GET FREE CHALLENGE

      Share Article
      About Author
      Shailendra Chauhan (Microsoft MVP, Founder & CEO at Scholarhat by DotNetTricks)

      Shailendra Chauhan is the Founder and CEO at ScholarHat by DotNetTricks which is a brand when it comes to e-Learning. He provides training and consultation over an array of technologies like Cloud, .NET, Angular, React, Node, Microservices, Containers and Mobile Apps development. He has been awarded Microsoft MVP 9th time in a row (2016-2024). He has changed many lives with his writings and unique training programs. He has a number of most sought-after books to his name which has helped job aspirants in cracking tough interviews with ease.
      Accept cookies & close this