Как проверить, реализует ли тип T IParsable<T>?

.NET 7 недавно представил IParsable в качестве интерфейса, и я хотел бы проверить его наличие. Некоторый тест, который вернет true, если T реализует IParsable<T>, и false в противном случае.

Скажем, я хочу вернуть объект типа T, когда T имеет метод Parse, например:

T ParseAs<T>(string s)
{
    if (typeof(IParsable<T>).IsAssignableFrom(typeof(T)))
    {
        return T.Parse(s);
    }
    else
    {
        //do something else...
    }
}

Я надеюсь, что это проверит, реализует ли T IParsable<T> и предоставит мне доступ к методам Parse и TryParse внутри. Кажется, я не могу использовать T в качестве аргумента типа для IParsable, вместо этого получая это исключение:

CS0314 Тип «T» нельзя использовать в качестве параметра типа «TSelf» в универсальном типе или методе «IParsable<TSelf>». Нет преобразования бокса или преобразования параметра типа из «T» в «System.IParsable<T>».

Я также получаю указанную выше ошибку, если пытаюсь использовать is:

s is IParsable<T>

Как бы я решил это?

Это помогает? stackoverflow.com/a/503359/1974021

DasKrümelmonster 19.11.2022 18:20

Это компилируется, но не позволяет мне выполнять T.Parse (ы) - знаете, почему это так?

Danatron1 19.11.2022 18:27
IParsable является рекурсивно определенным, поэтому вам нужно установить, что T есть IParsable<T>, прежде чем вы сможете сказать is IParsable<T>...
GSerg 19.11.2022 18:45

Правильно ли я вас понимаю, говоря, что прежде чем я смогу проверить, является ли T IParsable<T>, я должен знать, что T является IParsable<T>? Звучит как ловушка-22.

Danatron1 19.11.2022 18:50
Как настроить Tailwind CSS с React.js и Next.js?
Как настроить Tailwind CSS с React.js и Next.js?
Tailwind CSS - единственный фреймворк, который, как я убедился, масштабируется в больших командах. Он легко настраивается, адаптируется к любому...
LeetCode запись решения 2536. Увеличение подматриц на единицу
LeetCode запись решения 2536. Увеличение подматриц на единицу
Увеличение подматриц на единицу - LeetCode
Переключение светлых/темных тем
Переключение светлых/темных тем
В Microsoft Training - Guided Project - Build a simple website with web pages, CSS files and JavaScript files, мы объясняем, как CSS можно...
Отношения &quot;многие ко многим&quot; в Laravel с методами присоединения и отсоединения
Отношения &quot;многие ко многим&quot; в Laravel с методами присоединения и отсоединения
Отношения "многие ко многим" в Laravel могут быть немного сложными, но с помощью Eloquent ORM и его моделей мы можем сделать это с легкостью. В этой...
В PHP
В PHP
В большой кодовой базе с множеством различных компонентов классы, функции и константы могут иметь одинаковые имена. Это может привести к путанице и...
Карта дорог Беладжар PHP Laravel
Карта дорог Беладжар PHP Laravel
Laravel - это PHP-фреймворк, разработанный для облегчения разработки веб-приложений. Laravel предоставляет различные функции, упрощающие разработку...
4
4
100
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы иметь возможность использовать синтаксис T.Parse(), вам нужно знать во время компиляции, что T реализует IParseable<T>. Единственный способ убедиться в этом во время компиляции — явно сказать, что:

T ParseAs<T>(string s) where T: IParsable<T> {
    return T.Parse(s, null);
}

Если вы просто набрали T без явного указания, что это IParsable<T> - невозможно использовать синтаксис T.Parse, и вы должны использовать отражение полностью. Сначала вы проверяете, реализует ли T этот интерфейс с помощью отражения, а затем снова используете отражение для вызова этого статического метода:

T ParseAs<T>(string s) {
    var isParsable = typeof(T).GetInterfaces().Any(c => c.IsGenericType && c.GetGenericTypeDefinition() == typeof(IParsable<>));
    if (isParsable) {
        var parse = typeof(T).GetMethods(BindingFlags.Static | BindingFlags.Public)
            .FirstOrDefault(c => c.Name == "Parse" && c.GetParameters().Length == 2 && c.GetParameters()[0].ParameterType == typeof(string) && c.GetParameters()[1].ParameterType == typeof(IFormatProvider));
        if (parse != null)
            return (T) parse.Invoke(null, new object[] { s, null });
    }

    return default(T);
}

Это, конечно, довольно уродливо, и вы, вероятно, не захотите этого делать.

Подход с отражением был тем, который я использовал до этого обновления, и я хотел заменить его чем-то более элегантным. Спасибо за ответ - он точно отвечает на мой вопрос.

Danatron1 19.11.2022 19:57

Другие вопросы по теме