使用反射查找通用方法时发现模糊匹配
Ambiguous match found when using reflection to find Generic method
我正在使用反射来查找 Newtonsoft JsonConvert.DeserializedObject<T>
的通用方法,但我发现它返回了非通用版本 JsonConvert.DeserializeObject
的模糊匹配,这是试图获取泛型方法:
return typeof(JsonConvert).GetMethod("DeserializeObject", new Type[] { typeof(string) }).MakeGenericMethod(genericType);
我已经指定我想要使用 string
作为唯一参数的方法,但是通用和非通用版本都有匹配的参数列表,我收到了不明确的匹配错误。
这样使用GetMethod
是否可以获取通用版本?我知道我可以使用 Linq 和 GetMethods()
来找到它,例如:
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));
但是这样有点麻烦,一定有更好的办法。
我想你想要这个:
var method = typeof(JsonConvert).GetMethods().FirstOrDefault(
x => x.Name.Equals("DeserializeObject", StringComparison.OrdinalIgnoreCase) &&
x.IsGenericMethod && x.GetParameters().Length == 1)
?.MakeGenericMethod(genericType);
问题是 Type.GetMethod
不允许您指定泛型类型,这意味着此代码:
var method = typeof(JsonConvert).GetMethod("DeserializeObject", new[] { typeof(string)})
正在尝试在 JsonConvert.DeserializeObject(string)
和 JsonConvert.DeserializeObject<T>(string)
这两种匹配方法之间进行解析。
不幸的是,您无法使用 Linq 选项来执行此操作。
你可以从 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
}
用法:
var method = typeof(JsonConvert).GetMethod("DeserializeObject",
BindingFlags.Public | BindingFlags.Static,
new MyBinder(),
new[] {typeof(string)},
null);
在您的情况下 MyBinder
将在 SelectMethod
中收到两名候选人
public static object DeserializeObject(string value)
public static T DeserializeObject<T>(string value)
上面的代码将 select 第一个泛型方法
有 GetMethod
种方法可以区分泛型和非泛型方法;一个例子是 this one 和整数参数 genericParamCount
:
Searches for the specified public method whose parameters match the specified generic parameter count and argument types.
以下代码:
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);
将打印
System.String DeserializeObject[String](System.String)
System.Object DeserializeObject(System.String)
所以这可能是解决您问题的最短方法。
我正在使用反射来查找 Newtonsoft JsonConvert.DeserializedObject<T>
的通用方法,但我发现它返回了非通用版本 JsonConvert.DeserializeObject
的模糊匹配,这是试图获取泛型方法:
return typeof(JsonConvert).GetMethod("DeserializeObject", new Type[] { typeof(string) }).MakeGenericMethod(genericType);
我已经指定我想要使用 string
作为唯一参数的方法,但是通用和非通用版本都有匹配的参数列表,我收到了不明确的匹配错误。
这样使用GetMethod
是否可以获取通用版本?我知道我可以使用 Linq 和 GetMethods()
来找到它,例如:
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));
但是这样有点麻烦,一定有更好的办法。
我想你想要这个:
var method = typeof(JsonConvert).GetMethods().FirstOrDefault(
x => x.Name.Equals("DeserializeObject", StringComparison.OrdinalIgnoreCase) &&
x.IsGenericMethod && x.GetParameters().Length == 1)
?.MakeGenericMethod(genericType);
问题是 Type.GetMethod
不允许您指定泛型类型,这意味着此代码:
var method = typeof(JsonConvert).GetMethod("DeserializeObject", new[] { typeof(string)})
正在尝试在 JsonConvert.DeserializeObject(string)
和 JsonConvert.DeserializeObject<T>(string)
这两种匹配方法之间进行解析。
不幸的是,您无法使用 Linq 选项来执行此操作。
你可以从 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
}
用法:
var method = typeof(JsonConvert).GetMethod("DeserializeObject",
BindingFlags.Public | BindingFlags.Static,
new MyBinder(),
new[] {typeof(string)},
null);
在您的情况下 MyBinder
将在 SelectMethod
public static object DeserializeObject(string value)
public static T DeserializeObject<T>(string value)
上面的代码将 select 第一个泛型方法
有 GetMethod
种方法可以区分泛型和非泛型方法;一个例子是 this one 和整数参数 genericParamCount
:
Searches for the specified public method whose parameters match the specified generic parameter count and argument types.
以下代码:
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);
将打印
System.String DeserializeObject[String](System.String)
System.Object DeserializeObject(System.String)
所以这可能是解决您问题的最短方法。