Общий метод расширения 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.
Он использует отражение и, следовательно, может быть медленным, если производительность является проблемой.