Introduction: When the Code Says "I Don't Know"
\nImagine a scenario: you are writing a serialization library in C#. You have a method Serialize<T>(T obj) that can turn any object into a string. Everything is fine as long as you call it with a specific type: Serialize<User>(user). But what do you do if the type of the object becomes known only at runtime?
This is a classic problem asked by thousands of developers on Stack Overflow: "How do I call a generic method using a Type variable?". At first glance, the solution seems simple, but C# is a strongly typed language, and you cannot simply substitute a type variable into angle brackets.
\n\nIn this tutorial, we will break down how to correctly call generic methods using C# reflection with MakeGenericMethod. You will learn not only the syntax but also when it is truly necessary and when it is better to look for alternatives.
Why Can't You Just Write Method<type>()?
\nLet's dispel any illusions right away. The following code will not compile:
\nType runtimeType = someObject.GetType();\n// Compilation error: "'runtimeType' is a variable but is used like a type"\nSomeMethod<runtimeType>();\n\n\nWhy? Because generic parameters in C# are compile-time metadata. The compiler must know exactly which type it is working with to generate code. A Type variable is an object that exists only at runtime. To the compiler, it is just a variable, not a type.
The solution lies in reflection — a mechanism that allows you to inspect and invoke type members at runtime.
\n\nStep-by-Step Tutorial: Calling a Generic Method via Type
\nLet's break down the task with a concrete example. Suppose we have a service for processing data:
\npublic class DataProcessor\n{\n public string Process<T>(T data)\n {\n return $"Processed {typeof(T).Name}: {data}";\n }\n}\n\n\nWe want to call Process<T> when the type T is known only at runtime, for example, from typeof(string) or someObject.GetType().
Step 1. Get the MethodInfo for the Generic Method
\nFirst, we need to get the object representing our method:
\nDataProcessor processor = new DataProcessor();\nType processorType = typeof(DataProcessor);\n\n// Find the method by name. Important: specify BindingFlags if the method is not public\nMethodInfo? methodInfo = processorType.GetMethod("Process");\n\n\nImportant! If you have multiple method overloads, you will need to refine the search using GetMethods() and filtering. In our case, there is only one method — it's simple.
Step 2. Turn the Generic Method into a Concrete One Using MakeGenericMethod
\nHere it is, the main character of the article — the MakeGenericMethod method. It takes an array of types and returns a constructed (concrete) method:
Type runtimeType = typeof(int); // or any other type obtained dynamically\nMethodInfo? genericMethod = methodInfo?.MakeGenericMethod(runtimeType);\n\n\nNow genericMethod is a fully-fledged method Process<int>, ready to be called.
Step 3. Call the Method via Invoke
\nThe final step — using Invoke:
object? result = genericMethod?.Invoke(processor, new object[] { 42 });\nConsole.WriteLine(result); // Outputs: "Processed Int32: 42"\n\n\nNote:
\n- \n
- The first parameter of
Invokeis the object instance (for static methods —null). \n - The second parameter is an array of method arguments. Even if there is only one argument, it must be in an array. \n
- The result is returned as
object?— you may like