【问题标题】:IDataReader.GetOrdinal or IDataReader[ColumnName]IDataReader.GetOrdinal 或 IDataReader[ColumnName]
【发布时间】:2012-02-17 15:50:18
【问题描述】:

我有两种情况可以从 IDataReader 对象中提取信息

Case - 1 - 长度,计算序数然后解析字符串

public static string GetString(IDataReader rdr, string columnName)
{
    int ordinal = rdr.GetOrdinal(columnName);
    if (rdr.IsDBNull(ordinal))
    {
        return string.Empty;
    }
    return (string)rdr[ordinal];
}

案例2,短途,获取数据不计算序数

public static string GetString(IDataReader rdr, string columnName)
{
    return (string)rdr[columnName];
}

应该首选哪种技术,为什么以及如果有任何特定的上下文?

【问题讨论】:

  • 就我个人而言,我会使用第二个..也就是说,如果您不关心检查 columnName 是否存在..您是否总是确定得到非空值或非空值..??
  • Pavel 说的是对的,但是,您的函数不同之处在于它们返回 string.Empty 和 null,这可能会在您使用返回值时产生意想不到的结果。
  • @EricH 第二个示例将为空数据引发 InvalidCastException。您不能将 DBNull 转换为字符串。

标签: c# vb.net c#-4.0 idatareader


【解决方案1】:

SqlDataReader 的 this[string name] 看起来像:

public override object this[string name]
{
    get
    {
        return this.GetValue(this.GetOrdinal(name));
    }
}

所以它内部计算序数,使用什么方式没有区别。

更新

你可以将你的代码重写为:

public static string GetString(IDataReader rdr, string columnName)
{
    return (rdr[columnName] as String)??String.Empty;
}

【讨论】:

【解决方案2】:

这是您的第一个方法的 MSIL 外观:

.method public hidebysig static string  GetString(class [System.Data]System.Data.IDataReader rdr,
                                                  string columnName) cil managed
{
  // Code size       49 (0x31)
  .maxstack  2
  .locals init ([0] int32 ordinal,
           [1] string CS$1$0000,
           [2] bool CS$4$0001)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.1
  IL_0003:  callvirt   instance int32 [System.Data]System.Data.IDataRecord::GetOrdinal(string)
  IL_0008:  stloc.0
  IL_0009:  ldarg.0
  IL_000a:  ldloc.0
  IL_000b:  callvirt   instance bool [System.Data]System.Data.IDataRecord::IsDBNull(int32)
  IL_0010:  ldc.i4.0
  IL_0011:  ceq
  IL_0013:  stloc.2
  IL_0014:  ldloc.2
  IL_0015:  brtrue.s   IL_0020
  IL_0017:  nop
  IL_0018:  ldsfld     string [mscorlib]System.String::Empty
  IL_001d:  stloc.1
  IL_001e:  br.s       IL_002f
  IL_0020:  ldarg.0
  IL_0021:  ldloc.0
  IL_0022:  callvirt   instance object [System.Data]System.Data.IDataRecord::get_Item(int32)
  IL_0027:  castclass  [mscorlib]System.String
  IL_002c:  stloc.1
  IL_002d:  br.s       IL_002f
  IL_002f:  ldloc.1
  IL_0030:  ret
} // end of method Program::GetString

对于你的第二种方法:

.method public hidebysig static string  GetStringShort(class [System.Data]System.Data.IDataReader rdr,
                                                       string columnName) cil managed
{
  // Code size       18 (0x12)
  .maxstack  2
  .locals init ([0] string CS$1$0000)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.1
  IL_0003:  callvirt   instance object [System.Data]System.Data.IDataRecord::get_Item(string)
  IL_0008:  castclass  [mscorlib]System.String
  IL_000d:  stloc.0
  IL_000e:  br.s       IL_0010
  IL_0010:  ldloc.0
  IL_0011:  ret
} // end of method Program::GetStringShort

所以方法肯定不一样。至于哪个更好,你没有说为什么要计算序数,所以很难说哪个更适合你的情况。

【讨论】:

    【解决方案3】:

    我认为没有真正的区别(他们做同样的事情),第二个对我来说似乎更具可读性,因为“索引”的引入让那些不知道读者如何工作的人感到困惑。隐藏我说的不必要的复杂性。你应该更进一步,让它成为一个通用的,你可以在任何地方使用,就像这样:

        private static T FromDbValue<T>(IDataReader rdr, string columnName)
        {
            var value = rdr[columnName];
    
            if (value == DBNull.Value)
            {
                return default(T);
            }
    
            return (T)value;
        }
    

    调用它很容易:

    var someString = FromDbValue<string>(rdr, "CustomerName");
    

    编辑: 您没有在第二个示例中检查 DBNull,因此强制转换会因空值而失败。但是,总的来说,这两种方法是相同的。

    【讨论】:

    • 问题不在通用的上下文中,它是非通用的。您想分享任何链接吗?
    • 没有,我删掉了一些额外的代码并错过了。已移除。谢谢。
    • 请在相同的上下文中更新答案...或者您期待反对票...
    • 我不明白你的意思?我为我的方法提供了一个使用示例。如果您不能使用泛型,请使用您的方法。
    • 这可能是一个两行函数:var value = rdr[columnName];返回(值 == DBNull.Value)?默认(T):返回(T)值;
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-01
    • 2011-09-02
    • 1970-01-01
    相关资源
    最近更新 更多