Ответ 1
int variable = 0;
int.TryParse(stringValue, out variable);
Если он не может быть проанализирован, переменная будет равна 0. См. http://msdn.microsoft.com/en-us/library/f02979c7.aspx
Я хотел бы знать, есть ли "безопасный" способ конвертировать объект в int, исключая исключения.
Я ищу что-то вроде public static bool TryToInt32 (значение объекта, out int result);
Я знаю, что могу сделать что-то вроде этого:
public static bool TryToInt32(object value, out int result)
{
try
{
result = Convert.ToInt32(value);
return true;
}
catch
{
result = 0;
return false;
}
}
Но я предпочитаю избегать исключений, потому что они замедляют процесс.
Я думаю, что это более элегантно, но все равно "дешево".
public static bool TryToInt32(object value, out int result)
{
if (value == null)
{
result = 0;
return false;
}
return int.TryParse(value.ToString(), out result);
}
У кого-нибудь есть идея лучше?
UPDATE:
Это звучит немного как расщепление поиска волос. Но преобразование объекта в строку заставляет разработчика создавать четкую функцию ToString().
например:
public class Percentage
{
public int Value { get; set; }
public override string ToString()
{
return string.Format("{0}%", Value);
}
}
Percentage p = new Percentage();
p.Value = 50;
int v;
if (int.TryParse(p.ToString(), out v))
{
}
Это не так, я могу сделать две вещи здесь, или реализовать IConvertable, как показано ниже.
public static bool ToInt32(object value, out int result)
{
if (value == null)
{
result = 0;
return false;
}
if (value is IConvertible)
{
result = ((IConvertible)value).ToInt32(Thread.CurrentThread.CurrentCulture);
return true;
}
return int.TryParse(value.ToString(), out result);
}
Но ToInt32 IConvertible не может быть отменен. Поэтому, если это невозможно, исключение нельзя избежать.
или два: есть ли способ проверить, содержит ли объект неявный оператор?
Это очень плохо:
if (value.GetType().GetMethods().FirstOrDefault(method => method.Name == "op_Implicit" && method.ReturnType == typeof(int)) != null)
{
result = (int)value;
return true;
}
int variable = 0;
int.TryParse(stringValue, out variable);
Если он не может быть проанализирован, переменная будет равна 0. См. http://msdn.microsoft.com/en-us/library/f02979c7.aspx
Возвращаясь к комментариям. Ответ нет. Вы не можете делать то, что Convert.ToInt32(object)
делает, не выбрасывая исключения. Вы можете сделать что-то подобное (и вы уже это сделали). Единственное, что я бы оптимизировал, это вариант value
уже int
.
if (value is int)
return (int)value;
Вы не можете сделать как Convert.ToInt32(object)
, потому что Convert.ToInt32(object)
не просто проверяет, есть ли value
short, int, long, ushort, ...
, а затем отбрасывает их. Он проверяет, есть ли value
IConvertible
. Если да, то используется IConvertible.ToInt32
. К сожалению, интерфейс IConvertible
довольно низок: у него нет методов не метания (IConvertible.Try*
)
В то время как глупо (но, возможно, не слишком много), кто-то мог бы сделать, например, UnixDateTime
struct: (UnixTime - это количество секунд с полуночи 1970-01-01), где IConvertible.ToInt32
возвращает это количество секунд, а ToString()
возвращает форматированную дату. Все int.TryParse(value.ToString(), out parsed)
задохнутся, а Convert.ToInt32
будет работать безупречно.
Не нужно изобретать колесо здесь. используйте int.TryParse для достижения своей цели. Он возвращает bool, чтобы показать, что значение анализируется или нет. и при анализе результат сохраняется в выходной переменной.
int result;
object a = 5;
if(int.TryParse(a.ToString(),out result))
{
Console.WriteLine("value is parsed"); //will print 5
}
object b = a5;
if(int.TryParse(b.ToString(),out result))
{
Console.WriteLine("value is parsed");
}
else
{
Console.WriteLine("input is not a valid integer"); //will print this
}
Эта версия с использованием конвертера типов будет только преобразовывать в строку в качестве последнего средства, но также не вызывать исключения:
public static bool TryToInt32(object value, out int result)
{
if (value == null)
{
result = 0;
return false;
}
var typeConverter = System.ComponentModel.TypeDescriptor.GetConverter(value);
if (typeConverter != null && typeConverter.CanConvertTo(typeof(int)))
{
var convertTo = typeConverter.ConvertTo(value, typeof(int));
if (convertTo != null)
{
result = (int)convertTo;
return true;
}
}
return int.TryParse(value.ToString(), out result);
}
Я бы использовал смесь того, что вы уже делаете;
Полученный код:
public static bool TryToInt32(object value, out int result)
{
result = 0;
if (value == null)
{
return false;
}
//Try to convert directly
try
{
result = Convert.ToInt32(value);
return true;
}
catch
{
//Could not convert, moving on
}
//Try to parse string-representation
if (Int32.TryParse(value.ToString(), out result))
{
return true;
}
//If parsing also failed, object cannot be converted or paresed
return false;
}
Я написал этот беспорядок, глядя на него, и мне грустно.
using System;
using System.Globalization;
internal static class ObjectExt
{
internal static bool TryConvertToDouble(object value, out double result)
{
if (value == null || value is bool)
{
result = 0;
return false;
}
if (value is double)
{
result = (double)value;
return true;
}
var text = value as string;
if (text != null)
{
return double.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out result);
}
var convertible = value as IConvertible;
if (convertible == null)
{
result = 0;
return false;
}
try
{
result = convertible.ToDouble(CultureInfo.InvariantCulture);
return true;
}
catch (Exception)
{
result = 0;
return false;
}
}
}
Изменить Заметьте, теперь я ответил дважды, когда вопрос был int, сохраняя его в любом случае. Может быть, полезно для кого-то.