对于某些上下文,记录类SaleAmount属性为
public decimal? SaleAmount
{
get;
set;
}
理想情况下,我会选择
record.SaleAmount.Value =
sql.Reader.IsDBNull(IDX_SALEAMOUNT) ? null :
sql.Reader.GetDecimal(IDX_SALEAMOUNT);
唉,编译器,这不是朋友,因为......
无法确定条件表达式的类型,因为''和'十进制'之间没有隐式转换
那么你如何优雅地表达这一点,并且不要像下面那样玩明显的卡片......
if (!sql.Reader.IsDBNull(IDX_SALEAMOUNT))
record.SaleAmount = sql.Reader.GetDecimal(IDX_SALEAMOUNT);
或者高于最佳解决方案?
答案 0 :(得分:12)
如果您正在使用C#3,我实际上使用扩展方法可以让您更轻松:
public static decimal? GetNullableDecimal(this DbReader reader,
int column)
{
return reader.IsDBNull(column) ? (decimal?) null :
reader.GetDecimal(column);
}
然后您的应用程序代码可以使用:
record.SaleAmount = sql.Reader.GetNullableDecimal(IDX_SALEAMOUNT);
答案 1 :(得分:3)
你可以选择:
record.SaleAmount =
(sql.Reader.IsDBNull(IDX_SALEAMOUNT) ? null :
sql.Reader.GetDecimal(IDX_SALEAMOUNT)) as decimal?;
你可以尝试另一种方式:
// usage: new GenericDataReader(cm.ExecuteReader())
// ...Get<decimal?>(...);
public class GenericDataReader : IDataReader
{
// IDataReader implementation
public T Get<T>(int ordinal)
{
if (_dataReader.IsDBNull(ordinal))
return default(T);
else
return (T)_dataReader.GetValue(ordinal);
}
}
有关此方法的更多信息here。
答案 2 :(得分:3)
我喜欢使用以下通用扩展方法(可以很容易地转换为静态辅助函数)来从读取器获取可能的空值:
public static T Get<T>(this IDataReader reader, string columnName)
{
if (reader[columnName] == DbNull.Value)
{
return default(T);
}
return (T)reader[columnName];
}
答案 3 :(得分:2)
您收到该错误,因为类型decimal
(值类型)和null
(参考值)不能一起播放。
此外,由于您要分配Value
类型的Nullable<decimal>
媒体资源,因此您实际上是在尝试将null
分配给decimal
类型,是不行的。
您可以通过投射来明确地将GetDecimal
结果设为可为decimal
类型:
record.SaleAmount = sql.Reader.IsDBNull(IDX_SALEAMOUNT) ?
null : (decimal?)sql.Reader.GetDecimal(IDX_SALEAMOUNT);
我会采用你的第二种方法。
答案 4 :(得分:1)
首先,Value属性是只读的,所以无论如何你都无法分配它。
如果将一个强制转换添加到条件的false部分以转换为可以为null的十进制,编译器应该很高兴。请尝试以下
record.SaleAmount = sql.Reader.IsDBNull(IDX_SALEAMOUNT) ?
null : (decimal?) sql.Reader.GetDecimal(IDX_SALEAMOUNT);
答案 5 :(得分:0)
为什么不使用空合并运算符?
record.SaleAmount = (decimal?)sql.Reader.GetDecimal(IDX_SALEAMOUNT)
?? null;
答案 6 :(得分:0)
对我来说,最干净的解决方案是将它从业务逻辑层中完全删除,然后让查询首先向读者返回一个非空值
例如,如果使用SQL Server ..
SELECT IsNull(SalesAmount,0) ...
答案 7 :(得分:0)
我使用具有Nullable&lt; T&gt;的FieldHelper类。 ToXXX(对象)方法。这是 十进制的例子(这是在Linq之前的日子里写的 - 大约2 - 3年前, 欢迎您将委托构造替换为Linq):
/// <summary>
/// Gets a nullable value.
/// </summary>
/// <param name="aValue">The value to be converted.</param>
/// <returns>The converted value.</returns>
public static Nullable<decimal> ToDecimal(object aValue)
{
return ToNullable<decimal>(aValue,
delegate(object aConvertableValue)
{
return Convert.ToDecimal(aConvertableValue);
});
}
/// <summary>
/// Converts the given value if necessary.
/// </summary>
/// <param name="aValue">A value from the database.</param>
/// <param name="aConversion">A conversion delegate.</param>
/// <returns>null, or the given value.</returns>
private static Nullable<T> ToNullable<T>(
object aValue, Converter<T> aConverter) where T : struct
{
if (aValue == DBNull.Value || aValue == null)
return null;
else if (aValue is T)
return (T)aValue;
else
return aConverter(aValue);
}
答案 8 :(得分:0)
为了解决这个问题,不要在运行时开销方面花费太多,你恐怕不能太挑剔。
但是,语法更简洁:
public static Nullable<T> GetNullableValue<T>(this IDataRecord record,
int columnIndex, Func<int, T> getValue)
where T: struct;
{
if (record.IsDbNull(columnIndex))
return null;
else
return getValue(columnIndex);
}
var xyz = reader.GetNullableValue(0, reader.GetDecimal);
答案 9 :(得分:0)
IsDbNull(int)通常比使用GetSqlInt32等方法慢,然后比较DBNull.Value或使用它自己的.IsNull喜欢:
public static int Int32(this SqlDataReader r, int ord)
{
var t = r.GetSqlInt32(ord);
return t.IsNull ? default(int) : t.Value;
}
尝试了一些模板解决方案但到目前为止无济于事。问题是所有Sql类型(此处为SqlInt32)类型实际上是结构,而它们都有.Value属性C#没有真正的模板来处理它。它们也有自己的INullable接口,它只有.IsNull,并且与Nyllable&lt;&gt;不相容。
我怀疑人们需要完整的Sql类型作为C#模板,或者将ICOnvertible添加到它们中,以便能够只有一个或两个模板化方法。
如果有人可能有一个功能性技巧的想法或两个说出来:-)