Introdução: quando o código diz "não sei"
\nImagine a situação: você está escrevendo uma biblioteca de serialização em C#. Você tem o método Serialize<T>(T obj), que consegue transformar qualquer objeto em uma string. Tudo funciona perfeitamente enquanto você o chama com um tipo específico: Serialize<User>(user). Mas o que fazer quando o tipo do objeto só é conhecido durante a execução do programa?
Este é um problema clássico que milhares de desenvolvedores perguntam no Stack Overflow: "How do I call a generic method using a Type variable?". À primeira vista, a solução parece simples, mas C# é uma linguagem fortemente tipada, e simplesmente colocar uma variável de tipo entre colchetes angulares não funciona.
\n\nNeste tutorial, vamos abordar como chamar corretamente métodos genéricos através da reflexão em C# usando MakeGenericMethod. Você aprenderá não apenas a sintaxe, mas também quando isso é realmente necessário e quando é melhor buscar alternativas.
Por que não podemos simplesmente escrever Method<type>()?
\nVamos acabar com as ilusões imediatamente. O código a seguir não compila:
\nType runtimeType = someObject.GetType();\n// Erro de compilação: "O tipo 'runtimeType' não é válido"\nSomeMethod<runtimeType>();\n\n\nPor quê? Porque parâmetros genéricos em C# são metadados de tempo de compilação. O compilador precisa saber exatamente com qual tipo está trabalhando para gerar o código. A variável Type é um objeto que existe apenas em tempo de execução. Para o compilador, é apenas uma variável, não um tipo.
A solução está na área da reflexão — um mecanismo que permite inspecionar e invocar membros de tipos durante a execução.
\n\nTutorial passo a passo: chamando um método genérico através de Type
\nVamos analisar o problema com um exemplo concreto. Suponha que temos um serviço para processamento de dados:
\npublic class DataProcessor\n{\n public string Process<T>(T data)\n {\n return $"Processado {typeof(T).Name}: {data}";\n }\n}\n\n\nQueremos chamar Process<T> quando o tipo T é conhecido apenas em tempo de execução, por exemplo, a partir de typeof(string) ou someObject.GetType().
Passo 1. Obtendo o MethodInfo para o método genérico
\nPrimeiro, precisamos obter o objeto que representa nosso método:
\nDataProcessor processor = new DataProcessor();\nType processorType = typeof(DataProcessor);\n\n// Procuramos o método pelo nome. Importante: especificar BindingFlags se o método não for public\nMethodInfo? methodInfo = processorType.GetMethod("Process");\n\n\nImportante! Se você tiver várias sobrecargas do método, precisará refinar a busca usando GetMethods() e filtragem. No nosso caso, há apenas um método — é simples.
Passo 2. Transformando o método genérico em um método concreto com MakeGenericMethod
\nAqui está, o protagonista do artigo — o método MakeGenericMethod. Ele recebe um array de tipos e retorna um método construído (concreto):
Type runtimeType = typeof(int); // ou qualquer outro tipo obtido dinamicamente\nMethodInfo? genericMethod = methodInfo?.MakeGenericMethod(runtimeType);\n\n\nAgora, genericMethod é um método completo Process<int>, pronto para ser chamado.
Passo 3. Chamando o método através de Invoke
\nO toque final — usar Invoke:
object? result = genericMethod?.Invoke(processor, new object[] { 42 });\nConsole.WriteLine(result); // Exibirá: "Processado Int32: 42"\n\n\nObserve:
\n- \n
- O primeiro parâmetro de
Invokeé a instância do objeto (para métodos estáticos —null). \n - O segundo parâmetro é um array de argumentos do método. Mesmo que haja apenas um argumento, ele deve estar em um array. \n
- O resultado é retornado como
object?— você pode gostar