Question
In C#, how can you call a generic method when the type argument is not known at compile time, but is instead determined dynamically at runtime?
For example, in the following code, the Example() method gets a Type object from FindType(typeName). What is the correct and concise way to call GenericMethod<T>() using the type stored in myType?
How would the approach differ for calling the static method StaticMethod<T>()?
public class Sample
{
public void Example(string typeName)
{
Type myType = FindType(typeName);
// How do we call GenericMethod<T>() here?
// GenericMethod<myType>(); // This does not compile
// How do we call StaticMethod<T>() here?
// Sample.StaticMethod<myType>(); // This also does not compile
}
public void GenericMethod<T>()
{
// ...
}
public static void StaticMethod<T>()
{
// ...
}
}
Short Answer
By the end of this page, you will understand why GenericMethod<myType>() does not compile in C#, and how to call a generic method when the type is only known at runtime. You will learn how to use reflection with GetMethod(), MakeGenericMethod(), and Invoke() for both instance and static generic methods, along with common mistakes and practical patterns used in real codebases.
Concept
In C#, generic type arguments such as T are normally chosen at compile time. That means code like this works:
GenericMethod<int>();
because int is a known type when the code is compiled.
But this does not work:
Type myType = typeof(int);
GenericMethod<myType>();
The reason is that myType is a variable, not a type name in source code. C# generic syntax requires an actual type at compile time, not a Type object stored in memory.
When the type is only available at runtime, the usual solution is reflection.
The key reflection steps are:
- Find the generic method definition.
- Create a closed generic version of that method using
MakeGenericMethod(runtimeType). - Invoke the method.
Example idea:
MethodInfo method = typeof(Sample).GetMethod(nameof(GenericMethod));
MethodInfo closedMethod = method.MakeGenericMethod(myType);
closedMethod.Invoke(this, null);
This matters in real programs because runtime-selected types appear often:
- serializers and deserializers
- dependency injection frameworks
- plugin systems
- object mappers
- generic repositories
- data conversion utilities
Whenever code must adapt to types discovered dynamically, reflection is one of the main tools used.
Mental Model
Think of a generic method like a template machine.
GenericMethod<int>()means: “build the machine configured forint.”GenericMethod<string>()means: “build the machine configured forstring.”
At compile time, C# wants you to say exactly which machine you want.
A Type variable is more like a note in your hand that says which machine to build later. The compiler cannot use that note directly in generic syntax. Instead, reflection acts like a factory worker who reads the note at runtime and builds the correct version of the machine for you.
So:
- generic syntax (
<int>) = compile-time choice Typeobject (typeof(int)or runtime result) = runtime choice- reflection = bridge between the two
Syntax and Examples
Core syntax
To call a generic method using a runtime Type in C#, use reflection:
MethodInfo method = typeof(Sample).GetMethod(nameof(GenericMethod));
MethodInfo closedMethod = method.MakeGenericMethod(myType);
closedMethod.Invoke(this, null);
For a static generic method:
MethodInfo method = typeof(Sample).GetMethod(nameof(StaticMethod));
MethodInfo closedMethod = method.MakeGenericMethod(myType);
closedMethod.Invoke(null, null);
Complete example
using System;
using System.Reflection;
public class Sample
{
public void Example(string typeName)
{
Type myType = FindType(typeName);
MethodInfo instanceMethod = typeof(Sample).GetMethod(nameof(GenericMethod));
MethodInfo closedInstanceMethod = instanceMethod.MakeGenericMethod(myType);
closedInstanceMethod.Invoke(this, null);
MethodInfo staticMethod = typeof(Sample).GetMethod(nameof(StaticMethod));
MethodInfo closedStaticMethod = staticMethod.MakeGenericMethod(myType);
closedStaticMethod.Invoke(null, null);
}
public void GenericMethod<T>()
{
Console.WriteLine($"Instance generic method called with {typeof(T).Name}");
}
public static void StaticMethod<T>()
{
Console.WriteLine($"Static generic method called with {typeof(T).Name}");
}
private Type FindType(string typeName)
{
return typeName switch
{
"int" => typeof(int),
"string" => typeof(string),
_ => typeof(object)
};
}
}
What this example does
GetMethod()finds the method definition.MakeGenericMethod(myType)creates a version likeGenericMethod<int>()orGenericMethod<string>().Invoke()runs it.- For instance methods, pass
thisas the target. - For static methods, pass
nullas the target.
Step by Step Execution
Traceable example
using System;
using System.Reflection;
public class Sample
{
public void Example()
{
Type myType = typeof(string);
MethodInfo method = typeof(Sample).GetMethod(nameof(GenericMethod));
MethodInfo closedMethod = method.MakeGenericMethod(myType);
closedMethod.Invoke(this, null);
}
public void GenericMethod<T>()
{
Console.WriteLine(typeof(T).FullName);
}
}
Step by step
1. myType is assigned
Type myType = typeof(string);
Now myType stores the runtime type System.String.
2. The generic method definition is found
MethodInfo method = typeof(Sample).GetMethod(nameof(GenericMethod));
This gets metadata for the open generic method GenericMethod<T>().
3. A closed generic version is created
MethodInfo closedMethod = method.MakeGenericMethod(myType);
This produces the equivalent of:
GenericMethod<string>()
but built dynamically at runtime.
4. The method is invoked
closedMethod.Invoke(this, null);
thismeans call the method on the current object.nullmeans there are no normal method arguments.
5. The method runs
Inside the method:
Console.WriteLine(typeof(T).FullName);
Since T became string, the output is:
System.String
Real World Use Cases
Where this is used
Serializers
A serializer may discover the target type at runtime and need to call a generic method like:
Deserialize<T>()
Dependency injection containers
A DI framework may resolve services from a Type object and internally build calls to generic methods such as:
Resolve<T>()
Mapping libraries
Object mappers often receive source and destination types dynamically and may call generic conversion methods behind the scenes.
Plugin systems
A plugin loader might inspect assemblies, find types, and invoke generic registration methods based on discovered classes.
Data access helpers
A repository may need to call methods like:
GetEntity<T>()
when T comes from configuration, metadata, or reflection.
Testing tools and frameworks
Unit testing frameworks often discover test classes and invoke generic helper methods using runtime type information.
Real Codebase Usage
Common patterns in real projects
Guard clauses before reflection
Reflection can fail if the method is not found or the type is invalid. Real code often validates early:
if (myType == null)
throw new ArgumentNullException(nameof(myType));
MethodInfo method = typeof(Sample).GetMethod(nameof(GenericMethod))
?? throw new InvalidOperationException("Method not found.");
Caching MethodInfo
Reflection is slower than direct calls. In production code, developers often cache method metadata:
private static readonly MethodInfo GenericMethodDefinition =
typeof(Sample).GetMethod(nameof(GenericMethod));
Then reuse it instead of calling GetMethod() repeatedly.
Wrapping reflection in helper methods
Teams usually avoid scattering reflection code everywhere. Instead, they create a helper:
public void CallGeneric(Type type)
{
MethodInfo method = typeof(Sample).GetMethod(nameof(GenericMethod));
MethodInfo closed = method.MakeGenericMethod(type);
closed.Invoke(this, null);
}
Validation for generic constraints
If the generic method has constraints, code may validate them before calling MakeGenericMethod().
Error handling around Invoke
Invoke() may wrap exceptions in TargetInvocationException. Real code often unwraps or logs the inner exception.
Prefer non-reflection alternatives when possible
If the set of types is known, developers often use:
switchon known types- dictionaries of delegates
- interfaces or polymorphism
Reflection is usually chosen only when runtime flexibility is truly needed.
Common Mistakes
1. Trying to use a Type variable in generic syntax
This does not compile:
Type myType = typeof(int);
GenericMethod<myType>();
Why
Generic angle-bracket syntax expects a compile-time type, not a variable.
Fix
Use reflection:
MethodInfo method = typeof(Sample).GetMethod(nameof(GenericMethod));
MethodInfo closed = method.MakeGenericMethod(myType);
closed.Invoke(this, null);
2. Passing the wrong target to Invoke()
Broken code for an instance method:
closedMethod.Invoke(null, null);
Why
Instance methods need an object instance.
Fix
Use this or another object instance:
closedMethod.Invoke(this, null);
For static methods, null is correct.
3. Forgetting method arguments
If the method has parameters, they must be passed in the second argument array.
Broken example:
public void PrintValue<T>(T value) { }
closedMethod.Invoke(this, null);
Fix
Pass the arguments:
closedMethod.Invoke(this, new object[] { "hello" });
4. Using GetMethod() when there are overloads
If multiple methods have the same name, GetMethod(nameof(GenericMethod)) may not return the one you expect.
Fix
Use overload-specific lookup or filter the methods:
MethodInfo method = typeof(Sample)
.GetMethods()
.First(m => m.Name == nameof(GenericMethod) && m.IsGenericMethodDefinition);
5. Ignoring generic constraints
If a method is declared like this:
public void GenericMethod<T>() where T : class, new()
then not every runtime type is valid.
Fix
Make sure myType satisfies the constraints before calling MakeGenericMethod().
6. Not checking for null
Broken code:
MethodInfo method = typeof(Sample).GetMethod("MissingMethod");
MethodInfo closed = method.MakeGenericMethod(myType);
Why
If GetMethod() returns null, the next line crashes.
Fix
Check first:
MethodInfo method = typeof(Sample).GetMethod(nameof(GenericMethod))
?? throw new InvalidOperationException("GenericMethod not found.");
Comparisons
Generic call at compile time vs runtime
| Approach | When it works | Example | Pros | Cons |
|---|---|---|---|---|
| Direct generic call | Type is known at compile time | GenericMethod<int>() | Fast, simple, type-safe | Cannot use runtime Type values |
Reflection with MakeGenericMethod | Type is only known at runtime | method.MakeGenericMethod(myType).Invoke(...) | Flexible, works with dynamic type discovery | More verbose, less type-safe, slower |
Instance vs static generic method invocation
| Method kind | Target passed to Invoke() | Example |
|---|---|---|
| Instance method | Object instance | closed.Invoke(this, null) |
| Static method | null | closed.Invoke(null, null) |
Reflection vs alternative designs
| Option | Best for | Example idea | Tradeoff |
|---|---|---|---|
| Reflection | Unknown types discovered at runtime | plugins, serializers | Flexible but slower and more complex |
switch on known types | Small known set of types | if (type == typeof(int)) | Easy to read, but not scalable |
| Dictionary of delegates | Known runtime mappings | Dictionary<Type, Action> | Faster than reflection, but only for predefined types |
| Interfaces/polymorphism | Behavior attached to objects | handler.Handle() | Cleaner OO design, but not useful if all you have is a Type |
MakeGenericMethod vs MakeGenericType
| API | Used for | Example |
|---|---|---|
MakeGenericMethod | Generic methods | method.MakeGenericMethod(typeof(string)) |
MakeGenericType | Generic classes/types | typeof(List<>).MakeGenericType(typeof(string)) |
Cheat Sheet
Quick reference
Direct generic call
GenericMethod<int>();
Use this when the type is known at compile time.
Runtime generic call
MethodInfo method = typeof(Sample).GetMethod(nameof(GenericMethod));
MethodInfo closed = method.MakeGenericMethod(myType);
closed.Invoke(this, null);
Static runtime generic call
MethodInfo method = typeof(Sample).GetMethod(nameof(StaticMethod));
MethodInfo closed = method.MakeGenericMethod(myType);
closed.Invoke(null, null);
Rules
GenericMethod<myType>()is invalid becausemyTypeis a variable, not a compile-time type.- Use
MakeGenericMethod()for generic methods. - Use
MakeGenericType()for generic classes/types. - Pass an object instance to
Invoke()for instance methods. - Pass
nulltoInvoke()for static methods. - If the method has parameters, pass them as
object[]. - Check for
nullfromGetMethod(). - Be careful with overloaded methods.
- Generic constraints still apply at runtime.
Common pattern
MethodInfo method = typeof(MyClass).GetMethod(nameof(MyMethod))
?? throw new InvalidOperationException("Method not found.");
MethodInfo closed = method.MakeGenericMethod(runtimeType);
closed.Invoke(targetInstance, arguments);
FAQ
How do I call a generic method when I only have a Type object in C#?
Use reflection: find the method with GetMethod(), create a closed generic method with MakeGenericMethod(type), then call Invoke().
Why does GenericMethod<myType>() not compile?
Because C# generic syntax requires a type known at compile time. myType is a variable holding a Type value at runtime.
How do I invoke a static generic method with reflection?
Use the same reflection steps, but pass null as the target in Invoke().
What is the difference between MakeGenericMethod and MakeGenericType?
MakeGenericMethod is for generic methods. MakeGenericType is for generic classes or other generic types.
Is reflection the only way to do this?
If the type is truly unknown until runtime, reflection is the standard approach. If the possible types are known ahead of time, a switch, delegate map, or polymorphic design may be better.
Is calling generic methods with reflection slow?
It is slower than a direct method call. In many applications this is acceptable, but repeated reflection calls are often cached.
What happens if the generic method has constraints?
The runtime type must satisfy those constraints. Otherwise, MakeGenericMethod() or invocation will fail.
Can I call a generic method with parameters this way?
Yes. Pass normal method arguments as an object[] in Invoke() after creating the closed generic method.
Mini Project
Description
Build a small runtime type invoker that accepts a type name like "int", "string", or "DateTime", converts it into a Type, and then calls both an instance generic method and a static generic method using that runtime type. This demonstrates the exact reflection pattern used when generic arguments are discovered dynamically.
Goal
Create a C# class that finds a runtime type from a string and invokes ShowType<T>() and ShowStaticType<T>() using reflection.
Requirements
- Create a method that converts a type name string into a
Type. - Add one instance generic method and one static generic method.
- Use reflection to call both methods with the runtime type.
- Print the selected type name from inside each generic method.
- Handle the case where the type name is unknown.
Keep learning
Related questions
AddTransient vs AddScoped vs AddSingleton in ASP.NET Core Dependency Injection
Learn the differences between AddTransient, AddScoped, and AddSingleton in ASP.NET Core DI with examples and practical usage.
Best Way to Repeat a Character in C#: Building Repeated Strings Efficiently
Learn the best way to repeat a character in C#, compare StringBuilder, string concatenation, and simpler built-in options.
C# Access Modifiers and static: public, private, protected, and Defaults
Learn how C# public, private, protected, and default access control visibility, and how static differs from instance members.