Reputation: 2731
I know I can fetch the method info using GetMethods
, but I want to know how to do it properly without GetMethods
. I have read other SO questions and answers that suggest this is not possible, or suggest just using LINQ instead, but that isn't really an answer to the question.
Consider at the most basic level, a static generic function that takes a single generic parameter.
private static void Test<T>(T val)
{
}
To fetch this method info we can just call Type.GetMethod("Test", BindingFlags.Static | BindingFlags.NonPublic)
. However if there were some reason we could not use this simple GetMethod
signature (perhaps due to multiple overloads), then we need to supply the parameter types. The problem is that I cannot create a parameter type that accurately matches the T val
parameter. What's interesting is that I can take the parameters from the method info (fetched with GetMethods
) and pass that into GetMethod
to get the desired outcome. This means that if it were only possible to create the appropriate generic types (with IsGenericParameter
set to true) then I feel like this would be completely possible.
So that means that this is entirely possible in .NET, and only require the creation of the proper type instances. How does one create these type instances? And if they are not possible to create, why aren't they?
I created a simple fiddle to showcase the issue.
Upvotes: 6
Views: 2642
Reputation: 1
A bit late, but for future reference the following also works with .NET core
var flags = BindingFlags.Static | BindingFlags.NonPublic;
//the 0 indicates the index of the parameter
var paramTypes1 = new[] { Type.MakeGenericMethodParameter(0) };
var method = typeof(Program).GetMethod("Test", 1, flags, null, paramTypes1, null);
or simply
var method = typeof(Program).GetMethod("Test", 1, paramTypes1);
Suppose the method signature was
Test<T>(string val)
Then the paramTypes1 changes to
var paramTypes1 = new[] {typeof(string), Type.MakeGenericMethodParameter(0) };
even if the generic isn't a parameter per say it still needs to be mentioned in the array
Upvotes: 0
Reputation: 1064114
It isn't readily available, because the types you need are actually generic type arguments that only exist in the method / parameter definition. For example, in your Test<T>(T val)
, the parameter type is "the T
as defined by Test<T>
. You can't construct that, because it isn't composed from anything. The only way to obtain that T
is via GetParameters()
.
Basically, that leaves: the hard way - i.e. manually. For example:
var method1 = typeof(Program).GetMethods(flags).Single(x => x.Name == "Test"
&& x.IsGenericMethodDefinition && x.GetParameters().Length == 1
&& x.GetParameters()[0].ParameterType == x.GetGenericArguments()[0])
.MakeGenericMethod(paramTypes1);
Obviously it is simpler if you know there is only one Test(...)
method:
var method = typeof(Program).GetMethod("Test", flags)
.MakeGenericMethod(paramTypes1);
Upvotes: 8
Reputation: 4069
This isn't calling GetMethod but the "other" way to get a generic method definition is to "cast" a method group to a specific type, then call .Method.GetGenericDefinition()
on it.
In your example, the method signature you need is Action<object>
where object is just a placeholder and can be any type that matches the constraints of your generic method.
var genericMethodDefinition =
((Action<object>)Test<object>).Method.GetGenericMethodDefinition();
You might select a different overload of "Test" that is defined as private static T Test<T>(T val, int counter)
by using the following.
var genericMethodDefinition2 =
((Func<object, int, object>)Test<object>).Method.GetGenericMethodDefinition();
Upvotes: 4
Reputation:
Well, I don't think that it is possible.
But other approach (still hard way, I believe that GetMethods
would be better):
var method1 =
typeof (Program).GetMember("Test*",
BindingFlags.InvokeMethod |
BindingFlags.NonPublic |
BindingFlags.Static)
.Cast<MethodInfo>()
.Single(
m =>
m.GetGenericArguments().Length == 1 &&
m.GetGenericArguments()[0].IsGenericParameter)
.MakeGenericMethod(paramTypes1);
Of course, you can omit MakeGenericMethod
to get exacly the same result as method2
.
Upvotes: 1