При использовании отражения для поиска общего метода найдено неоднозначное совпадение - PullRequest
0 голосов
/ 24 октября 2018

Я использую отражение, чтобы найти универсальный метод для 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));

Но это немного громоздко, должен быть лучший способ.

Ответы [ 3 ]

0 голосов
/ 24 октября 2018

Проблема в том, что Type.GetMethod не позволяет вам указать универсальный тип, означающий, что этот код:

var method = typeof(JsonConvert).GetMethod("DeserializeObject", new[] { typeof(string)})

пытается разрешить между двумя подходящими методами JsonConvert.DeserializeObject(string) и JsonConvert.DeserializeObject<T>(string).

К сожалению, вы застряли с опцией Linq, чтобы сделать это.

0 голосов
/ 24 октября 2018

Вы можете получить от Binder класса

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)

Приведенный выше код выберет первый общий метод

0 голосов
/ 24 октября 2018

Я думаю, вы хотите это:

var method = typeof(JsonConvert).GetMethods().FirstOrDefault(
    x => x.Name.Equals("DeserializeObject", StringComparison.OrdinalIgnoreCase) &&
    x.IsGenericMethod && x.GetParameters().Length == 1)
    ?.MakeGenericMethod(genericType);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...