Sharif Rezvani
Sharif Rezvani

Reputation: 261

How can I add a method to a list of actions via reflection?

I have created a dot net fiddle that shows the requirement in action.

Basically I have a lot of business classes that inherit from a base class. And I want to be able to dynamically add logic to all of them to be executed after they create entities.

In this specific case, I want to able to log entities that are created.

This is my code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

var businessClasses = typeof(IEntity)
    .Assembly
    .GetTypes()
    .ToList()
    .Where(i => i.BaseType != null)
    .Where(i => i.BaseType.Name.StartsWith("Business"))
    .ToList();
Console.WriteLine(businessClasses.Count);
foreach (var businessClass in businessClasses)
{
    var postCreationAugmenters = businessClass.GetField("PostCreationAugmenters", BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Static).GetValue(null);
    // how can I add the LogAugmenter.LogCreation to the postCreationAugmenters list?
}

public static class LogAugmenter
{
    public static void LogCreation(IEntity entity)
    {
    }
}


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

public class Blog : IEntity
{
    public long Id { get; set; }
}

public class Business<T>
    where T : IEntity
{
    public static List<Action<T>> PostCreationAugmenters = new List<Action<T>>();
    public T Create(T entity)
    {
        // Inserting the model inside the database and returning it with the assigned Id
        foreach (var augmenter in PostCreationAugmenters)
        {
            augmenter.Invoke(entity);
        }

        return entity;
    }
}

public class BlogBusiness : Business<Blog>
{
    
}

How can I add the LogAugmenter.LogCreation to the postCreationAugmenters list that is extracted via reflection.

Upvotes: 0

Views: 193

Answers (1)

thehennyy
thehennyy

Reputation: 4218

You have to take the following steps to add your method to the generic list:

  1. Get the target method.
  2. Create a matching delegate for the method.
  3. Get the List.Add method.
  4. Invoke the List.Add and pass the create delegate.

Have a look at this example, but as mentioned in the comments, i think you gain nothing by choosing this design. Going with a typesafe approach using interfaces will save you from a lot of hard to maintain and debug reflection calls.

foreach (var businessClass in businessClasses)
{
    var postCreationAugmenters = businessClass.GetField("PostCreationAugmenters", BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Static).GetValue(null);

    // how can I add the LogAugmenter.LogCreation to the postCreationAugmenters list?
    var targetMethod = typeof(LogAugmenter).GetMethod(nameof(LogAugmenter.LogCreation));
    var targetMethodDelegate = Delegate.CreateDelegate(typeof(Action<>).MakeGenericType(businessClass.BaseType.GetGenericArguments()), targetMethod);
    var listAddMethod = postCreationAugmenters.GetType().GetMethod("Add");
    listAddMethod.Invoke(postCreationAugmenters, new object[] { targetMethodDelegate });
}

Upvotes: 3

Related Questions