Как определить, является ли строка числом в C # - PullRequest
11 голосов
/ 20 ноября 2008

Я работаю над инструментом, в котором мне нужно преобразовать строковые значения в соответствующие им типы объектов. Например. преобразовать строку типа "2008-11-20T16:33:21Z" в DateTime значение. Числовые значения, такие как "42" и "42.42", должны быть преобразованы в значения Int32 и Double соответственно.

Каков наилучший и наиболее эффективный подход для определения, является ли строка целым числом или числом? Int32.TryParse или Double.TryParse путь?

Ответы [ 4 ]

20 голосов
/ 20 ноября 2008

Int.TryParse и Double.TryParse имеют преимущество фактического возврата номера.

Что-то вроде Regex.IsMatch("^\d+$") имеет недостаток, заключающийся в том, что вам все равно придется снова анализировать строку, чтобы получить значение.

9 голосов
/ 20 ноября 2008

С точки зрения эффективности, да, как правило, предпочтительным является 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 голосов
/ 20 ноября 2008

Я бы порекомендовал .TryParse () лично. Это то, что я использую в любом случае. Это если ваши данные будут неправильными время от времени. Если вы уверены, что входящие строки смогут без затруднений конвертировать в целые или двойные числа, .Parse () быстрее.

Вот интересная ссылка для поддержки этого.

0 голосов
/ 20 ноября 2008

Сохраняя идею конвертера, чтобы пропустить блок переключателей, вы можете использовать концепцию 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

Остальное

...