Общий метод расширения TryParse

Код взят здесь

Я хотел бы услышать некоторые экспертные мнения по этому методу расширения. Я планирую использовать его, но хотел бы услышать о любых известных проблемах, с которыми я могу столкнуться.

Я лучше использовать примитивные методы TryParse?

public static T? TryParse<T>(this object obj) where T : struct
        {
            if (obj == null) return null;

            T? result = null;
            TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
            if (converter != null)
            {
                try
                {
                    string str = obj.ToString();
                    result = (T)converter.ConvertFromString(str);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }

            return result;
        }

5 ответов

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

public static bool TryParse<T>(string s, out T value) {
    TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
    try {
        value = (T) converter.ConvertFromString(s);
        return true;
    } catch {
        value = default(T);
        return false;
    }
}

Обратите внимание, я принял string здесь, потому что это то, что я обычно имею в виду под TryParse; иначе, Convert.ChangeType может быть более подходящим.

Я не вижу причин для этого быть методом расширения (согласно this в примере вопроса), и, конечно, не рекомендуется загрязнять object со слишком многими методами расширения.

Расширения ниже могут быть полезны для вас. Они работают с любым типом, который имеет метод Parse или TryParse...

Они приходят из моей библиотеки расширений здесь: http://www.codeproject.com/KB/dotnet/MBGExtensionsLibrary.aspx

Хотя этот проект, вероятно, немного устарел... Мне придется обновить его как-то:-D

Надеюсь это поможет!

public static class StringExtensions
    {
        public static TOut ParseOrDefault<TOut>(this string input)
        {
            return input.ParseOrDefault(default(TOut));
        }
        public static TOut ParseOrDefault<TOut>(this string input, TOut defaultValue)
        {
            Type type = typeof(TOut);
            MethodInfo parseMethod = type.GetMethod("Parse", new Type[] { typeof(string) });

            if (parseMethod != null)
            {
                var value = parseMethod.Invoke(null, new string[] { input });
                return (value is TOut ? (TOut)value : defaultValue);
            }
            else { return defaultValue; }
        }
        public static bool TryParseOrDefault<TOut>(this string input, out TOut output)
        {
            return input.TryParseOrDefault(out output, default(TOut));
        }
        public static bool TryParseOrDefault<TOut>(this string input, out TOut output, TOut defaultValue)
        {
            output = defaultValue;

            Type type = typeof(TOut);
            MethodInfo parseMethod = type.GetMethod(
                "TryParse",
                new Type[] { typeof(string), typeof(TOut).MakeByRefType() });

            if (parseMethod != null)
            {
                object[] parameters = new object[] { input, output };
                var value = parseMethod.Invoke(null, parameters);

                if (value is bool)
                {
                    bool successful = (bool)value;
                    if (successful)
                    {
                        output = (TOut)parameters[1];
                        return true;
                    }
                }
            }
            return false;
        }
    }

Обобщения наиболее полезны, когда вы хотите изменить публичный контракт метода или класса, а внутренности метода или класса на самом деле не заботятся (или сильно заботятся) о типе, который изменяется.

Некоторые примеры:

List<T> это коллекция, в которую можно помещать вещи, и внутри класса классу не очень важно, что это за тип.

T System.Linq.Enumerable.First<T>(IEnumerable<T> source) возвращает первый элемент из набора элементов. Этот метод не должен знать внутренне, какой это тип, чтобы выполнить работу.

В отличие от этого, метод синтаксического анализа должен изменить свое поведение в зависимости от типа результата. В предоставленном методе есть Стратегия, которая выталкивает поведение в другие методы, но для этого выбора существуют затраты времени выполнения.

Альтернатива состоит в том, чтобы позволить вызывающей стороне (которая должна знать тип, или они не могли вызвать универсальный метод с ним), выбрать конвертер. Этот выбор может быть сделан во время разработки или компиляции и, следовательно, требует 0 затрат времени выполнения.

Примечание: пожалуйста, не используйте повторную идиому. Все, что он делает, это сбрасывает стек вызовов, и вы никогда не захотите этого делать.

catch (Exception ex)
{
  throw ex;
}

Для более простого кода вы можете сделать это:

T value = (T)Convert.ChangeType(value, typeof(T));

Благодарим Томаса Левеска по адресу /questions/42865423/kak-dinamicheski-privesti-obekt-tipa-stroka-k-obektu-tipa-t/42865437#42865437.

Он использует отражение и, следовательно, может быть медленным, если производительность является проблемой.

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