Есть ли способ сделать это лучше / чище?
int stockvalue = 0;
if (!Convert.IsDBNull(reader["StockValue"]))
stockvalue = (int)reader["StockValue"];
Есть ли способ сделать это лучше / чище?
int stockvalue = 0;
if (!Convert.IsDBNull(reader["StockValue"]))
stockvalue = (int)reader["StockValue"];
Самый короткий (ИМХО):
int stockvalue = (reader["StockValue"] as int?) ?? 0;
Объяснение:
int? stockvalue = reader["StockValue"] as int?
- person stevehipwell; 12.03.2010
int x = (int)obj
ваш код сломается при изменении типа столбца, что позволит вам исправить его на double x = (double)obj
; @JohnSaunders правильно поднимает красный флаг, поскольку подход as int?
незаметно поглотит это изменение; вы могли бы поймать его, только если бы кто-то заметил нулевое значение там, где его быть не должно.
- person phoog; 24.02.2012
Я справляюсь с этим так
int? stockvalue = reader["StockValue"] as int?;
Очень просто, чисто и в одну линию. Если по какой-то причине у меня абсолютно не может быть нулевого значения (что я обычно считаю плохим аргументом, поскольку я бы предпочел знать, имеет ли значение значение или оно было унифицировано для примитивного типа), я бы сделал:
int stockvalue = (reader["StockValue"] as int?).GetValueOrDefault(-1);
(int?) reader["ColumnName"]
, и я начал искать правильный способ сделать это. Это следует принять как ответ.
- person Anlo; 28.03.2013
Несколько дней назад я написал метод расширения. Используя его, вы могли просто:
int? stockvalue = reader.GetValue<int?>("StockValue");
Вот метод расширения (измените в соответствии с вашими потребностями):
public static class ReaderHelper
{
public static bool IsNullableType(Type valueType)
{
return (valueType.IsGenericType &&
valueType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)));
}
public static T GetValue<T>(this IDataReader reader, string columnName)
{
object value = reader[columnName];
Type valueType = typeof(T);
if (value != DBNull.Value)
{
if (!IsNullableType(valueType))
{
return (T)Convert.ChangeType(value, valueType);
}
else
{
NullableConverter nc = new NullableConverter(valueType);
return (T)Convert.ChangeType(value, nc.UnderlyingType);
}
}
return default(T);
}
}
int? stockvalue = (int?)(!Convert.IsDBNull(result) ? result : null);
Одно из возможных решений, позволяющее убедиться, что DBNull переносится в ваш код. Для нашей группы мы стараемся не разрешать столбцы NULL в базе данных, если это действительно не нужно. Чтобы справиться с этим, требуется больше накладных расходов на кодирование, а иногда просто переосмысление проблемы делает ее ненужной.
Да, вы можете использовать int?
. Таким образом, вы можете иметь значение по умолчанию null вместо 0. Поскольку результатом stockvalue потенциально может быть 0, не возникает путаницы относительно того, была ли база данных нулевой или нулевой. Например, как это (предварительно обнуляемое), у нас была инициализация по умолчанию -1, чтобы представить, что значение не было присвоено. Лично я подумал, что это немного опасно, потому что, если вы забудете установить его на -1, возникнет проблема с повреждением данных, которую может быть очень сложно отследить.
http://msdn.microsoft.com/en-us/library/2cf62fcy(VS.80).aspx
int? stockvalue = null;
if (!Convert.IsDBNull(reader["StockValue"]))
stockvalue = (int)reader["StockValue"];
//Then you can check
if(stockValue.HasValue)
{
// do something here.
}
DBNull
все еще нужно преобразовать в null
с небольшой проверкой.
- person Jon Seigel; 12.03.2010
Хотя ссылаться на reader["StockValue"]
удобно, это не очень эффективно. Он также не является строго типизированным, поскольку возвращает тип object
.
Вместо этого в своем коде сделайте что-то вроде этого:
int stockValueOrdinal = reader.GetOrdinal("StockValue");
int? stockValue = reader.IsDbNull(stockValueOrdinal) ?
null :
reader.GetInt32(stockValueOrdinal);
Конечно, лучше всего получить все порядковые номера одновременно, а затем использовать их во всем коде.
Вот один способ.
int stockvalue = Convert.IsDbNull(reader["StockValue"]) ? 0 : (int)reader["StockValue"];
Вы также можете использовать TryParse
int stockvalue = 0
Int32.TryParse(reader["StockValue"].ToString(), out stockvalue);
Сообщите нам, какой способ работает для вас
Вы можете выполнить это преобразование прямо в своем запросе к базе данных, тем самым полностью избегая особого случая.
Но я бы не назвал это «чище», если только вы не сможете последовательно использовать эту форму в своем коде, поскольку вы потеряете информацию, вернув из БД «0» вместо NULL.
используйте Nullable<int>
тип ..._ 2_ для краткости
Не совсем. Вы можете инкапсулировать это в методе:
public int getDBIntValue(object value, int defaultValue) {
if (!Convert.IsDBNull(value)) {
return (int)value;
}
else {
return defaultValue;
}
И назовите это так:
stockVaue = getDBIntVaue(reader["StockValue"], 0);
Или вы можете использовать coalesce
в своем запросе, чтобы возвращаемое значение было ненулевым.
Edit - исправлены ошибки тупого кода на основе полученных комментариев.
getDBIntValue
всегда будет пытаться извлечь int
из reader["StockValue"]
, независимо от того, что передано. У вас также есть ключевое слово default
в качестве одного из ваших параметров, который не будет компилироваться (вам нужно будет сделать это @default
или - - лучше - просто смени название).
- person Dan Tao; 12.03.2010
Convert.IsDBNull(reader["StockValue"])
независимо от переданного параметра. Таким образом, он всегда будет смотреть на reader["StockValue"]
, а не на любой другой столбец в любой другой таблице. Это было то, что я указывал, а не то, что он возвращает int
(что, как вы правильно указываете, должно быть очевидным).
- person Dan Tao; 12.03.2010
В моем проекте есть два следующих метода расширения:
public static T GetValueSafe<T>(this IDataReader dataReader, string columnName, Func<IDataReader, int, T> valueExtractor)
where T : class
{
T value;
if (dataReader.TryGetValueSafe(columnName, valueExtractor, out value))
{
return value;
}
return null;
}
public static bool TryGetValueSafe<T>(this IDataReader dataReader, string columnName, Func<IDataReader, int, T> valueExtractor, out T value)
{
int ordinal = dataReader.GetOrdinal(columnName);
if (!dataReader.IsDBNull(ordinal))
{
// Get value.
value = valueExtractor.Invoke(dataReader, ordinal);
return true;
}
value = default(T);
return false;
}
Использование может быть таким:
string companyName = dataReader.GetValueSafe("CompanyName", (reader, ordinal) => reader.GetString(ordinal));
reader.Get<int>("ReaderField")
и работает с использованием метода ChangeType
.
- person Chris Marisic; 12.03.2010