当使用DataReader时,TryParse是个坏主意吗?
本文关键字:TryParse DataReader | 更新日期: 2023-09-27 17:51:11
所以,我一直在阅读一些代码,看到了一个有趣的模式,用于解析来自数据阅读器的数据。它看起来像:
public static long ParseLong(IDataReader reader, string field, long default)
{
long result;
var value = GetValue(reader, field);
if (value == DBNull.Value) return default;
// is this next line bad?
if (Int64.TryParse(value.ToString(), out result)) return result;
return default;
}
这个模式不适合我,因为它隐藏了类型转换异常,似乎转换到字符串然后再次转换将比仅仅调用"Convert.ToInt64(value)"要慢。
我错了吗?是否有更好的模式来解析来自数据阅读器的数据?
注 -在我的例子中,列的类型是"NUMBER(20)"。即使情况并非如此,最好还是抛出异常,以便开发人员在投入生产之前修复问题,对吧?
是的,很糟糕。
如果列已经是sql数字类型之一,这不仅是缓慢的方法,而且如果机器的数字格式使用了一些奇怪的分隔字符,它可能会引入错误。如果您知道该列已经是一个数字,则应该将其强制转换为long
。
另一方面,这个方法没有上下文可用。从方法的角度来看,该列可以是任何东西。事实上,我们经常会发现,有些人在设计数据库时,想要使用字符串类型(nvarchar等)来处理所有事情,尽管这可能是一种误导。这段代码确实有一个小优点,如果列使用字符串类型来保存数值数据,它仍然可以工作,并且允许想要真正泛型的方法使用这种技术是公平的(尽管我个人可能希望先尝试强制转换,然后只有在强制转换失败时才回退到字符串技术)。
然而,这段代码中还有另一个问题:DBNull检查。如果要将转换为字符串并解析它,则null检查是多余的。DBNull.Value.ToString()返回一个空字符串,这将使TryParse()调用失败,并导致返回默认长度,与检查相同。代码是不需要的。
因此,我们现在处于这样一种情况,它要么因为字符串转换而不好,要么如果你允许字符串转换,它因为空检查而不好。不管怎样,它都失败了。我接受这段代码的唯一原因是,如果您可以证明您确实需要字符串转换,并且在分析之后,您会发现程序花费了大量不必要的时间将DBNull转换为字符串。然后添加更快的null检查就可以了。
根据您的编辑,我有一点要为这段代码辩护。快速检查long类型的文档会发现,long类型的最大值为19位。你最多可以存20个。所以这段代码可能是为了防止9,223,372,036,854,775,807和99,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999之间的非常大的值,这些值适合列,但不适合长类型…尽管在这种情况下,我更倾向于为这些值抛出异常,而不是仅仅返回0。
最后一个想法。这段代码工作是因为IDataReader
实现了IDataRecord
接口。该方法应该只请求一个IDataRecord
,以使其更灵活。
没有理由通过字符串解析值,因为它可以隐藏数据错误。你可以使用你的方法的泛型变体:
public static T Parse<T>(IDataReader reader, string field, T default)
{
int columnIndex = reader.GetOrdinal(field);
if (reader.IsDBNull(columnIndex)) return default;
return (T)reader.GetValue(columnIndex);
}
IDataRecord
接口为您提供了特定类型的读取,而不是使用IDataRecord.GetInt64
方法读取,但您也必须检查DBNull。