【问题标题】:ADO.NET convert Decimal(4,2) to double using GenericsADO.NET 使用泛型将 Decimal(4,2) 转换为双精度
【发布时间】:2014-04-30 18:48:26
【问题描述】:

我正在尝试使用将字段转换为泛型类型的自定义方法将存储在 SQL Server 数据库中的 decimal(4,2) 字段转换为 C# double。 (方法是SqlDataReader类的扩展。)

当我运行代码时,我不断收到错误“指定的强制转换无效”。

方法如下:

public static T Get<T>(this SqlDataReader reader, string field) 
{
    try {
        int index = reader.GetOrdinal(field);
        if (reader.IsDBNull(index)) return default(T);

        T item = (T)reader[index];
        return item;
    } catch (Exception e) {
        Console.WriteLine(e); 
        return default(T); 
    }
}

在我调用方法的地方,我正在将值直接读入类构造函数中,例如:

// reader is a SqlDataReader instance with an open connection, and fields obtained via the 'Read()' method.
MyClass myObject = new MyClass(reader.Get<double>("My_Field"));

SqlDataReader 中有正确的数据。 index 变量设置为正确的字段序号,在调试时我可以运行 reader[1]; 行并获得正确的返回值,例如:0 或 6.1。

失败的数据库中的一些值是:0.00、1.00、6.1。

我想找出导致此问题的原因并在通用方法中修复它(到目前为止,它已适用于所有其他常见数据类型),因为它旨在简化 ADO 并使其更易于阅读,而不是常规的糟糕的“样板”ADO。

【问题讨论】:

  • 你说的失败是什么意思?如果有例外,您应该提供例外情况。
  • 对于DataRow 已经是具有相同想法的扩展方法DataRow.Field<Decimal>("MyFieldName")
  • 异常错误是:“指定的转换无效”。我没有在任何地方写“归档”...?

标签: c# sql sql-server sql-server-2008 ado.net


【解决方案1】:

您不能将盒装小数转换为双精度;您必须先将其转换为未装箱的小数。您可以使用 Convert 类来做您想做的事情:

public static T Get<T>(this SqlDataReader reader, string field) 
{
    try {
        int index = reader.GetOrdinal(field);
        if (reader.IsDBNull(index)) return default(T);

        object item = reader[index];
        return item is T ? (T)item : (T)Convert.ChangeType(item, typeof(T));
    } catch (Exception e) {
        Console.WriteLine(e); 
        return default(T); 
    }
}

我敢肯定有些情况下这不能处理,但它应该足以让你开始。

【讨论】:

  • 非常好,似乎适用于我的所有测试。诚然,总会有一些无关紧要的案件,但我必须在它们出现时处理它们。谢谢!
  • @LoganDangerBlack 我想到了这段代码的一个重要潜在问题(这实际上是从 DataReader 读取数据的过程中固有的):如果你在数字列中有一个 DbNull,这段代码将转换它为零。因此,最好将该方法称为reader.Get&lt;double?&gt;("My_Field")
  • 好收获。我在大多数有意义的地方都使用了可为空的包装器。 (我的数据库将允许空值。)
【解决方案2】:

问题是你在双重施法(我在这里可能没有使用正确的术语)。

reader[index] 返回一个object,它不能直接转换为double。必须先将其转换为 decimal。

decimal dec = 1.0M;
object obj = dec;

var x = (double)dec; //succeeds
var y = (double)obj; //fails

我不确定是否有解决此问题的方法,除了使用您的通用函数来获取存储在表中的值的实际类型,然后转换为您想要存储它的变量的类型。

(double)reader.Get<decimal>("My_Field"))

【讨论】:

  • 是的,我使用(double)reader.Get&lt;decimal&gt;("My_Field") 行作为临时修复。理想情况下,我想永久解决它,但正如@Fabio 所说,我的简单通用方法就在窗外......
  • 我觉得不对。 object o =10; decimal d = (decimal)o; 使用此代码我得到同样的错误
  • @gmailuser 那是因为您的 o 包含对盒装 int 的引用,该引用不能直接转换为小数。必须先拆箱。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-13
  • 2010-10-16
  • 2012-09-23
  • 2015-02-12
  • 1970-01-01
  • 1970-01-01
  • 2019-03-18
相关资源
最近更新 更多