Reputation: 14618
I'm using reflection to find the generic method for Newtonsoft JsonConvert.DeserializedObject<T>
but am finding that it's returning an ambiguous match for the non-generic version JsonConvert.DeserializeObject
, here is the code which tries to get the generic method:
return typeof(JsonConvert).GetMethod("DeserializeObject", new Type[] { typeof(string) }).MakeGenericMethod(genericType);
I've specified that I want the method which takes a string
as its only argument but both the generic and non-generic version have matching parameter lists, and I receive the ambiguous match error.
Is it possible to to get the generic version using GetMethod
in this way? I know I can use Linq and GetMethods()
to find it e.g:
var method = typeof(JsonConvert).GetMethods().FirstOrDefault(
x => x.Name.Equals("DeserializeObject", StringComparison.OrdinalIgnoreCase) &&
x.IsGenericMethod && x.GetParameters().Length == 1 &&
x.GetParameters()[0].ParameterType == typeof(string));
But this is a bit cumbersome, there must be a better way.
Upvotes: 10
Views: 8404
Reputation: 22641
There are GetMethod
methods which do distinguish between generic and non-generic methods; an example is this one with the integer parameter genericParamCount
:
Searches for the specified public method whose parameters match the specified generic parameter count and argument types.
The following code:
var genericMethod = typeof(JsonConvert)
.GetMethod("DeserializeObject", 1, new Type[] { typeof(string) })
.MakeGenericMethod(typeof(string));
var otherMethod = typeof(JsonConvert)
.GetMethod("DeserializeObject", 0, new Type[] { typeof(string) });
Console.WriteLine(genericMethod);
Console.WriteLine(otherMethod);
will print
System.String DeserializeObject[String](System.String)
System.Object DeserializeObject(System.String)
so this is perhaps the shortest solution to your problem.
Upvotes: 5
Reputation: 7054
You can derive from Binder
class
class MyBinder : Binder
{
public override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
{
return match.First(m => m.IsGenericMethod);
}
#region not implemented
public override MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state) => throw new NotImplementedException();
public override FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture) => throw new NotImplementedException();
public override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers) => throw new NotImplementedException();
public override object ChangeType(object value, Type type, CultureInfo culture) => throw new NotImplementedException();
public override void ReorderArgumentArray(ref object[] args, object state) => throw new NotImplementedException();
#endregion
}
Usage:
var method = typeof(JsonConvert).GetMethod("DeserializeObject",
BindingFlags.Public | BindingFlags.Static,
new MyBinder(),
new[] {typeof(string)},
null);
In your case MyBinder
will receive two candidates in SelectMethod
public static object DeserializeObject(string value)
public static T DeserializeObject<T>(string value)
Code above will select first generic method
Upvotes: 3
Reputation: 118977
The problem is that Type.GetMethod
doesn't allow you to specify the generic type meaning that this code:
var method = typeof(JsonConvert).GetMethod("DeserializeObject", new[] { typeof(string)})
is trying to resolve between the 2 matching methods JsonConvert.DeserializeObject(string)
and JsonConvert.DeserializeObject<T>(string)
.
Unfortunately you are stuck with the Linq option to do this.
Upvotes: 2
Reputation: 313
I think you want this:
var method = typeof(JsonConvert).GetMethods().FirstOrDefault(
x => x.Name.Equals("DeserializeObject", StringComparison.OrdinalIgnoreCase) &&
x.IsGenericMethod && x.GetParameters().Length == 1)
?.MakeGenericMethod(genericType);
Upvotes: 5