2009-02-09 5 views

ответ

64

Unboxing работает только в том случае, если тип идентичен! Вы не можете распаковать object, который не содержит целевое значение. Что вам нужно что-то вдоль линий

decimal tmpvalue; 
decimal? result = decimal.TryParse((string)value, out tmpvalue) ? 
        tmpvalue : (decimal?)null; 

Это выглядит ли интерпретируемое как decimal значение. Если да, то назначьте его result; иначе назначьте null. Следующий код делает примерно то же самое и, возможно, будет легче понять, для людей, не знакомых с условным оператором ?::

decimal tmpvalue; 
decimal? result = null; 
if (decimal.TryParse((string)value, out tmpvalue)) 
    result = tmpvalue; 
+2

Я не использовал бы слово «идентичный» здесь.Например, вы можете распаковать между типами перечислений и их базовым типом, T и T ?, и некоторые другие нечетные случаи IIRC. CLR является более разрешительным, чем можно было бы ожидать. –

+0

(Но да, вы не должны ожидать unboxing для разбора строки :) –

+0

@Jon: у вас есть лучшая формулировка? Не имея этого, я собираюсь скопировать ваш комментарий в свой ответ, потому что он выражает оговорку красиво. –

2

и если вы используете decimal? temp = (decimal?)value;

+0

это не работает. Я не могу объяснить, почему. В debugmode Visual Studio хочет показать разборку ... – Natrium

+1

Это очень странно, потому что он отлично работает на моей стороне ..... – StevenMcD

+0

Это не сработает, если значение содержит экземпляр строки. Он должен работать, если он содержит экземпляр десятичной дроби. – pauloya

5

вы должны разобрать десятичную. Но если вы хотите, чтобы ваш десятичный утратившей когда строка не является правильной, используйте TryParse:

decimal parsedValue; 
decimal? temp = decimal.TryParse(value, out parsedValue) 
       ? value 
       : (decimal?)null; 

Таким образом, вы будете избегать исключений во время разбора плохо отформатированных строк.

Практически все примитивные типы предоставляют методы Parse и TryParse для преобразования из строки.

Также рекомендуется передать культуру для аргумента поставщика методу, чтобы избежать проблем с разделителем десятичной дроби. Если вы читаете из другой системы, CultureInfo.InvariantCulture - это, вероятно, путь (но это не значение по умолчанию).

bool TryParse(string s, NumberStyles style, 
    IFormatProvider provider, out decimal result) 
+0

Я забыл (десятичный?) Бросок для нуля ... извините, но часть культуры по-прежнему важна. – thinkbeforecoding

+3

Этот ответ неверен, поскольку присвоение 'значения' 'temp' не будет работать. Должен быть ? parsedValue: (десятичный?) null; – offner

1

Если вы не хотите, чтобы разобрать строки, но хотите, чтобы убедиться, что вы получите либо null, decimal или обнуляемым decimal, то вы могли бы сделать что-то вроде этого:

public static Nullable<T> Convert<T>(object input) 
    where T : struct 
{ 
    if (input == null) 
     return null; 
    if (input is Nullable<T> || input is T) 
     return (Nullable<T>)input; 
    throw new InvalidCastException(); 
} 

Вы могли бы заставьте его возвращать значение null в последней строке, если вы хотите избежать исключений, хотя это не будет отличать реальные нулевые значения и плохие отбрасывания.

Обратите внимание, что вам нужно использовать оператор «is», так как оператор «as» не работает с типами значений, а литье без проверки может вызвать InvalidCastException.

Вы можете также сделать его метод расширения:

public static class ObjectExtensions 
{ 
    public static Nullable<T> ToNullable<T>(this object input) 
     where T : struct 
    { 
     if (input == null) 
      return null; 
     if (input is Nullable<T> || input is T) 
      return (Nullable<T>)input; 
     throw new InvalidCastException(); 
    } 
} 

И использовать его как это:

object value = 123.45m; 
decimal? dec = value.ToNullable<decimal>(); 

Это поможет избежать кода контрактным предупреждения о ссылках распаковки нуля.

+0

Вы протестировали свой метод расширения? Я попробовал это и получил исключение NullReferenceException для действительного двойного значения, которое необходимо было преобразовать в десятичную цифру с нулевым значением. – Shiva

+0

@Shiva. Метод расширения не предназначен для удвоений, поскольку он указывает в первой строке: «вы получаете либо нуль, либо десятичную или нулевая десятичная дробь " –

Смежные вопросы