使用DataReader时,TryParse是个坏主意吗?

时间:2014-03-21 13:24:14

标签: c# casting datareader

所以,我一直在阅读一些代码,看到了一个有趣的模式,用于解析数据读取器中的数据。它看起来像:

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;
}

这种模式并不适合我,因为它隐藏了类型转换异常,似乎转换为字符串然后再次转换将比调用"转换.ToInt64(值)&#34慢;

我是否在此基础上?是否有更好的模式来解析数据读取器中的数据?

注意 - 在我的情况下,列的类型是" NUMBER(20)"。即使这不是这种情况,最好抛出异常,以便开发人员在投入生产之前解决问题,对吗?

2 个答案:

答案 0 :(得分:3)

是的,这很糟糕。

如果列已经是sql数字类型之一,这不仅是执行它的慢速方法,而且如果机器的数字格式使用一些奇怪的分隔符,它可能会引入错误。如果您知道该列已经是一个数字,那么您应该将其转换为long

另一方面,此方法没有可用的上下文。从方法的角度来看,该列可以是任何内容。事实上,找到那些想要为所有事情使用字符串类型(nvarchar等)的人设计的数据库是相当普遍的,但这可能是错误的。这个代码确实有一个很小的优点,如果列使用字符串类型来保存数字数据它仍然可以工作,并且允许一个想要真正通用的方法来使用这种技术是公平的(尽管我个人可能想要先尝试强制转换,然后仅在转换失败时才回退到字符串技术。)

但是,此代码中还有另一个问题:DBNull检查。 如果您要转换为字符串并解析它,则空检查是多余的。 DBNull.Value.ToString()返回一个空字符串,它将使TryParse()调用失败并导致返回默认long,与check一样。代码是不需要的。

因此,我们现在处于由于字符串转换而导致错误的情况,或者如果允许字符串转换,则由于空检查而导致错误。它无论如何都失败了。我接受此代码的唯一原因是,如果您可以证明您确实需要字符串转换,并且在分析后发现该程序花费了大量时间,不必要地将DBNull转换为字符串。然后添加更快的空检查就可以了。

根据您的编辑,我确实有一点可以保护此代码。快速检查docs for the long type表示长的最大值最高为19位。您最多可存储20个。因此,此代码可以在那里试图防止9,223,372,036,854,775,807和99,999,999,999,999,999,999之间的非常大的值,这些值确实适合列但不适合长类型。 ..虽然即使在这种情况下,我的偏好是为这些值抛出异常,而不是仅仅返回0。

最后一个想法。此代码有效,因为IDataReader实现了IDataRecord接口。该方法应该只是要求IDataRecord,以使其更灵活。

答案 1 :(得分:1)

没有理由通过字符串解析值,因为它可以隐藏数据错误。 您使用方法的泛型变体:

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。