Search code examples
c#genericsreflectiongeneric-method

Ambiguous match found when using reflection to find Generic method


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.


Solution

  • 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