When you work with dynamic types or runtime code generation, reflection quickly becomes both powerful and confusing. I faced a real puzzle recently β€” how to invoke a generic method that itself returns a generic Action delegate, and then call that delegate at runtime.


βš™οΈ The Setup

Suppose you have a helper like this:

public static class FastInvoke
{
    public static Action<T, object> BuildUntypedSetter<T>(MemberInfo member)
    {
        var instance = Expression.Parameter(typeof(T), "obj");
        var value = Expression.Parameter(typeof(object), "val");

        var access = Expression.MakeMemberAccess(instance, member);
        var convert = Expression.Convert(value, ((PropertyInfo)member).PropertyType);
        var body = Expression.Assign(access, convert);

        return Expression.Lambda<Action<T, object>>(body, instance, value).Compile();
    }
}

This dynamically builds a setter for any property on any type β€” a neat reflection shortcut that compiles to IL at runtime.


🧩 The Problem

Now imagine we’re building a dynamic type with TypeBuilder, and we want to call the setter without knowing the type at compile time:

var type = MyTypeBuilder.CompileResultType(dtTempAttendance, true);
var obj = Activator.CreateInstance(type);
var prop = type.GetProperty("EmployeeName");

We find the method via reflection:

var method = typeof(FastInvoke)
    .GetMethod("BuildUntypedSetter")
    .MakeGenericMethod(type);

var setter = method.Invoke(null, new[] { prop }) as Action<object, object>;

But β€” surprise!
setter is always null.

Why? Because Action<SomeType, object> β‰  Action<object, object>.
Generic delegate types are not automatically compatible.


πŸ” The Discovery

The fix wasn’t to force-cast (which fails), but to treat the result as a Delegate and invoke it dynamically.

var del = method.Invoke(null, new[] { prop }) as Delegate;
del.DynamicInvoke(obj, "Test Value");

That worked β€” though it sacrifices some of the β€œfast” in FastInvoke.

If performance matters, the proper way is to generate a uniform wrapper (e.g., a cached dictionary of compiled lambdas per type) instead of generic invocation per call.


🧰 Practical Takeaway

  1. Generic Actions are not covariant β€” Action<T, object> and Action<object, object> are distinct.
  2. If you only know the type at runtime, use Delegate or DynamicInvoke().
  3. To retain performance, build a delegate cache keyed by type once, not per call.

πŸ’‘ Bonus Tip: When Reflection Meets JSON

In my actual scenario, I sidestepped the reflection headache entirely by serializing the data into JSON and parsing it client-side. Sometimes, the practical solution is simpler than the theoretical one!


Author: Algolassi
Posted on: October 9, 2025
Category: C#, Reflection, Dynamic Programming
Tags: c#, reflection, generics, delegates

πŸ€– AlgoLassi Assistant Have a question about this tutorial?

Ask AlgoLassi and get an answer plus the tutorials worth studying next.

Ask a question

πŸ’¬ Comments

Sign in with Google to publish immediately, or comment anonymously and wait for approval.

Comments will appear here when available.