Универсальный TryParse

197

Я пытаюсь создать универсальное расширение, которое использует TryParse, чтобы проверить, является ли строка данного типа:

public static bool Is<T>(this string input)
{
    T notUsed;
    return T.TryParse(input, out notUsed);
}

это не скомпилируется, так как не может разрешить символ «TryParse»

Как я понимаю, «TryParse» не является частью какого-либо интерфейса.

Можно ли вообще это сделать?

Обновить:

Используя ответы ниже, я придумал:

public static bool Is<T>(this string input)
{
    try
    {
        TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(input);
    }
    catch
    {
        return false;
    }

    return true;
}

Это работает довольно хорошо, но я думаю, что использование исключений таким образом не подходит мне.

Update2:

Изменен для передачи типа, а не для использования обобщений:

public static bool Is(this string input, Type targetType)
{
    try
    {
        TypeDescriptor.GetConverter(targetType).ConvertFromString(input);
        return true;
    }
    catch
    {
        return false;
    }
}
Пирс Майерс
источник
1
Я думаю, что в этом общем случае вам просто придется иметь дело с исключением Kludge. Вы можете добавить кейсы, чтобы проверять такие вещи, как int или double, а затем использовать определенные методы TryParse, но вам все равно придется воспользоваться этим, чтобы перехватывать другие типы.
Люк
1
Использование общего не является необходимым. Просто введите тип в качестве параметра. public static bool Is (это строка ввода, типа targetType). Этот способ вызова выглядит немного красивее: x.Is (typeof (int)) -VS- x.Is <int> ()
mikesigs
2
В конвертере есть метод IsValid, чтобы вы могли проверить, не возникнут ли проблемы с конвертацией. Я использовал метод ниже и, кажется, работает нормально. protected Boolean TryParse<T>(Object value, out T result) { result = default(T); var convertor = TypeDescriptor.GetConverter(typeof(T)); if (convertor == null || !convertor.IsValid(value)) { return false; } result = (T)convertor.ConvertFrom(value); return true; }
CastroXXL
@CastroXXL Спасибо за проявленный интерес к этому вопросу, однако ваш метод не вполне сработает, так как я хотел проверить, было ли строковое значение определенного типа, а не объекта, хотя ваш метод был бы полезен для типов объектов (но нужно обернуть ConvertFrom(value)метод в try-catchблоке, чтобы поймать исключения.
Пирс Майерс
2
Вы должны проверить, если (targetType == null), потому что первое использование этого в вашем коде может выдать, но это исключение будет поглощено вашим уловом.
Ник Струпат,

Ответы:

183

Вы должны использовать класс TypeDescriptor :

public static T Convert<T>(this string input)
{
    try
    {
        var converter = TypeDescriptor.GetConverter(typeof(T));
        if(converter != null)
        {
            // Cast ConvertFromString(string text) : object to (T)
            return (T)converter.ConvertFromString(input);
        }
        return default(T);
    }
    catch (NotSupportedException)
    {
        return default(T);
    }
}
Люк
источник
3
Извините, что воскресил, но GetConverter возвращает ноль? Я думаю, что если это произойдет, то, вероятно, следует выдать исключение, а не просто молча потерпеть неудачу и вернуть что-то еще. Когда я попробовал это на своем собственном классе (в котором я не определил преобразователь типов), я получил преобразователь от GetConverter, но затем ConvertFromString выдал исключение NotSupportedException.
user420667
3
@ user420667, я полагаю, что вы должны проверить результат CanConvertFrom (typeof (string)), прежде чем пытаться конвертировать из строки. TypeConverter может не поддерживать преобразование из строки.
Рувим Бонд
3
Вы можете добавить if (typeof (T) .IsEnum) {return (T) Enum.Parse (typeof (T), input); } [как довольно общий ярлык для всех типов Enum] до получения конвертера. Я полагаю, это зависит от того, как часто вы будете использовать типы Enum, в отличие от более сложных типов.
Джесси Чисхолм
10
Я не понимаю, почему это помечается как ответ и так часто голосуется, когда не реализует то, что было запрошено: универсальный Try Parse. Основная цель методов TryParse состоит в том, что они не выдают исключений при попытке выполнить синтаксический анализ и оказывают гораздо меньшее влияние на производительность в случае сбоя синтаксического анализа, и это решение не может обеспечить именно это.
Флорин Думитреску
2
Одна из проблем с этим заключается в том, что если T является целым числом, а входное значение больше, чем int.MaxValue, оно будет выдавать исключение System.Exception с System.OverFlowException в качестве внутреннего исключения. Поэтому, если вы ожидаете OverflowException, вы не получите его, если не запросите выброшенное исключение. Причина в том, что ConvertFromString создает исключение OverflowException, а затем приведение к T создает исключение System.Exception.
Тревор