How to dynamically Create Generic C# Object Using Reflection

In this post, we’ll explore how to dynamically create instances of generic classes using C# reflection. This technique can be handy when you need to work with generic types where the type arguments are not known at compile time. We’ll demonstrate how to achieve this by using the MakeGenericType method and the Activator.CreateInstance method.

Creating Instances of Generic Classes: When dealing with generic classes, the actual type arguments may not be known until runtime. To create an instance of a generic class dynamically, you can follow these steps:

  1. Retrieve the Generic Type Definition: First, obtain the generic type definition. This is the type that includes the open generic type parameter(s), represented by placeholders like T or TKey.

    Type genericTypeDefinition = typeof(List<>);
    
  2. Specify Type Arguments: Define the type arguments you want to use. These type arguments will replace the open generic type parameters in the generic type definition.

    Type[] typeArgs = { typeof(string) };
    
  3. Create the Closed Generic Type: Use the MakeGenericType method to create a closed generic type by combining the generic type definition with the specified type arguments.

    Type closedGenericType = genericTypeDefinition.MakeGenericType(typeArgs);
    
  4. Instantiate the Generic Type: Finally, use the Activator.CreateInstance method to create an instance of the closed generic type.

    object instance = Activator.CreateInstance(closedGenericType);
    
  5. Type Casting: Depending on your requirements, you might want to cast the instance to the specific generic type to work with its members.

    List<string> typedInstance = instance as List<string>;
    

Example Code Snippet: Here’s the complete code snippet demonstrating how to create an instance of a generic class using C# reflection:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Type genericTypeDefinition = typeof(List<>);
        Type[] typeArgs = { typeof(string) };
        Type closedGenericType = genericTypeDefinition.MakeGenericType(typeArgs);
        object instance = Activator.CreateInstance(closedGenericType);
        List<string> typedInstance = instance as List<string>;

        Console.WriteLine("Instance created: " + (typedInstance != null));
    }
}

Real-World Example: Repository Pattern with Different Data Types

The Scenario

Suppose you have the following scenario:

  • You have defined a generic interface IRepository<T> with methods like Add and GetById.
  • There are concrete implementations of this interface: UserRepository and ProductRepository.
  • Each implementation handles a specific entity type (User and Product) and provides corresponding methods.

The Code

Let’s dive into the code that demonstrates how to dynamically create instances of these classes based on a given entity type:

using System;
using System.Linq;
using System.Reflection;

public interface IRepository<T>
{
    void Add(T entity);
    T GetById(int id);

}

public class UserRepository : IRepository<User>
{
    public void Add(User entity) { /* Implementation */ }
    public User GetById(int id) { return new User { Id = 1 }; }
   
}

public class ProductRepository : IRepository<Product>
{
    public void Add(Product entity) { /* Implementation */ }
    public Product GetById(int id) { return new Product { Id = 1 }; }
}

public interface IEntity
{
    int Id { get; set; }
}

public class User : IEntity
{
    public int Id { get; set; }
}

public class Product : IEntity
{
    public int Id { get; set; }
}

class Program
{
    static void Main()
    {
        Type repositoryType = typeof(IRepository<>);
        Type entityType = typeof(Product);

        Type closedRepositoryType = repositoryType.MakeGenericType(entityType);

        // Find and create an instance of a class implementing the IRepository<T> interface
        var repositoryImplementationType = Assembly.GetExecutingAssembly().GetTypes()
            .FirstOrDefault(type =>
                !type.IsAbstract && !type.IsInterface &&
                type.GetInterfaces()
                    .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == repositoryType && i.GetGenericArguments()[0] == entityType));

        if (repositoryImplementationType != null)
        {
            var repositoryInstance = Activator.CreateInstance(repositoryImplementationType);

            Console.WriteLine($"Repository instance created: {repositoryImplementationType.Name}");
        }
        else
        {
            Console.WriteLine("No suitable repository implementation found.");
        }
    }
}

Explanation

The code begins by defining the generic interface IRepository<T> and providing concrete implementations for entities User and Product.

In the Main method, we specify the generic repository type IRepository<> and the desired entity type (Product in this case). We then use reflection to find a class that implements the desired repository interface with the specified entity type argument. If a suitable implementation is found, we create an instance of that class and display its name.

Conclusion

Dynamic instantiation of generic classes using reflection can be extremely useful in scenarios where the type arguments are determined at runtime. By combining MakeGenericType and Activator.CreateInstance, you can easily work with generic types in a flexible and dynamic manner. Just remember that reflection has performance overhead, so use it judiciously.

Post a Comment

Please do not post any spam link in the comment box😊

Previous Post Next Post

Blog ads

CodeGuru