Как определить, является ли строка числом в С#
Я работаю над инструментом, где мне нужно преобразовать строковые значения в соответствующие типы объектов. Например. преобразуйте строку как "2008-11-20T16:33:21Z"
в значение DateTime
. Числовые значения, такие как "42"
и "42.42"
, должны быть преобразованы в значение Int32
и значение Double
соответственно.
Каков наилучший и наиболее эффективный способ определения, является ли строка целым числом или числом? Есть ли Int32.TryParse
или Double.TryParse
путь?
Ответы
Ответ 1
Что касается эффективности, да, TryParse обычно является предпочтительным маршрутом.
Если вы можете узнать (например, путем отражения) тип цели заранее - но не хотите использовать большой блок switch
, вам может быть интересно использовать TypeConverter
- например:
DateTime foo = new DateTime(2008, 11, 20);
TypeConverter converter = TypeDescriptor.GetConverter(foo);
string s = converter.ConvertToInvariantString(foo);
object val = converter.ConvertFromInvariantString(s);
Ответ 2
Int.TryParse
и Double.TryParse
имеют преимущество от фактического возврата числа.
Что-то вроде Regex.IsMatch("^\d+$")
имеет недостаток, что вам все равно придется разбирать строку еще раз, чтобы получить значение.
Ответ 3
Я бы рекомендовал .TryParse() лично. Это то, что я использую. Это, если ваши данные будут ошибочными снова и снова. Если вы уверены, что входящие строки смогут конвертировать в целые числа или удваивать без заминки, то .Parse() выполняется быстрее.
Здесь интересная ссылка для поддержки этого.
Ответ 4
Сохраняя идею перехода преобразователя на блок переключателей, вы можете использовать концепцию Duck Typing. В принципе, вы хотите превратить строку в X, поэтому вы создаете метод, который будет вызывать X.TryParse(string, out X x), если X имеет TryParse на нем, иначе вы просто не беспокоитесь (или, я полагаю, вы могли бы бросить ошибка). Как бы вы это сделали? Отражение и дженерики.
В принципе, у вас будет метод, который будет принимать тип и использовать отражение, чтобы увидеть, есть ли у него TryParse. Если вы найдете такой метод, вы вызываете его и возвращаете то, что удалось получить TryParse. Это хорошо работает с любым типом значения, например, Decimal или DateTime.
public static class ConvertFromString
{
public static T? ConvertTo<T>(this String numberToConvert) where T : struct
{
T? returnValue = null;
MethodInfo neededInfo = GetCorrectMethodInfo(typeof(T));
if (neededInfo != null && !numberToConvert.IsNullOrEmpty())
{
T output = default(T);
object[] paramsArray = new object[2] { numberToConvert, output };
returnValue = new T();
object returnedValue = neededInfo.Invoke(returnValue.Value, paramsArray);
if (returnedValue is Boolean && (Boolean)returnedValue)
{
returnValue = (T)paramsArray[1];
}
else
{
returnValue = null;
}
}
return returnValue;
}
}
Где GetCorrectMethodInfo будет выглядеть примерно так:
private static MethodInfo GetCorrectMethodInfo(Type typeToCheck)
{
MethodInfo returnValue = someCache.Get(typeToCheck.FullName);
if(returnValue == null)
{
Type[] paramTypes = new Type[2] { typeof(string), typeToCheck.MakeByRefType() };
returnValue = typeToCheck.GetMethod("TryParse", paramTypes);
if (returnValue != null)
{
CurrentCache.Add(typeToCheck.FullName, returnValue);
}
}
return returnValue;
}
И использовать будет:
decimal? converted = someString.ConvertTo<decimal>();
Я ненавижу подключать себя, но я полностью объяснил здесь:
GetCorrectMethodInfo
Остальная часть