Как определить, является ли строка числом в С#

Я работаю над инструментом, где мне нужно преобразовать строковые значения в соответствующие типы объектов. Например. преобразуйте строку как "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

Остальная часть