C# 如何处理所有DBNull而不必每次检查它们(使用生成的数据集)?

C# 如何处理所有DBNull而不必每次检查它们(使用生成的数据集)?,c#,.net,dbnull,C#,.net,Dbnull,正如@nicholas正确指出的,我最初的问题有点误导,因为这个案件有点具体 所以真正的问题是: 我使用DataGridView控件和从生产数据库中的表生成的数据源创建了Windows窗体应用程序 我的程序的目标是查看表,有选择地编辑注释列,并将表数据导出到XML文件,该模式是使用XSD和其他我无法更改的独立约束严格定义的 特别重要的是,如果没有定义某些值,我不能在XML输出文件中插入某些字段 它明确地说我不能为这些字段插入空标记。这就是我需要空值的原因。仅在给定值的位置插入XML标记。这就是为

正如@nicholas正确指出的,我最初的问题有点误导,因为这个案件有点具体

所以真正的问题是:

我使用DataGridView控件和从生产数据库中的表生成的数据源创建了Windows窗体应用程序

我的程序的目标是查看表,有选择地编辑注释列,并将表数据导出到XML文件,该模式是使用XSD和其他我无法更改的独立约束严格定义的

特别重要的是,如果没有定义某些值,我不能在XML输出文件中插入某些字段

它明确地说我不能为这些字段插入空标记。这就是我需要空值的原因。仅在给定值的位置插入XML标记。这就是为什么我需要DBNull值,而不是任何其他默认值

生成的数据集包含在访问DBNull值时引发异常的getter。我不能更改生成的代码,这是一条规则,您不能更改生成的代码,尤其是可能(并且将)被覆盖的代码

我通过用“try/catch”块围绕一个可空字段的每个赋值来解决这个问题。如果生成的getter抛出异常,我的XML对象的可空字段将保留它的默认空值,这是我的预期行为

稍后-我的XML构造函数将在生成XML输出时跳过这些字段

但有一个问题仍然存在:为什么它必须如此丑陋?如果我有一百个可为空的字段呢?我需要写一百个“try/catch”块吗?在我看来,这似乎是整个微软机制中的一个缺陷。或者有一个简单而优雅的解决方案

-- 以下是原始内容,以了解第一个答案的来源:

拜托,我知道我可以检查每个字段的DBNull,但必须有 这是程序员的一种自动方式。这将是最愚蠢的事情 在整个.NET/C中——必须为 我的大桌子的每一列!我试着在我的桌子上用“foreach” 行类型,但它不起作用。异常是在最底层抛出的 “foreach”身体的开始,如果我试图触摸DBNull, 异常被抛出。如果我把整个代码块放进去 “try/catch”-它不会工作,因为它会跳过后面的所有字段 第一个DBNull

一定有办法做到这一点,而不是把几十个失败 签入我的代码。那么,对于与之成排的人来说,什么是魔术呢 DBNulls

编写扩展名:

public static T GetValue<T>(this IDataRecord @this, string name, T defaultValue = default(T))
{
    int ordinal = @this.GetOrdinal(name));
    return @this.GetValue<T>(ordinal, defaultValue);
} 

public static T GetValue<T>(this IDataRecord @this, int ordinal, T defaultValue = default(T))
{
    return @this.IsDBNull(ordinal) ? defaultValue : (T)@this.GetValue(ordinal);
} 

通过修改SQL select查询以调用
IsNull
(或者在访问后端
Nz
)在从服务器检索DbNull值之前删除DbNull值


假设您有某种适当的默认值,或者稍后使用sentinel值来捕获空值。

编写一个函数来提取该值,如果DBNull,则编写一个默认值,并在需要读取列时使用它可能会有所帮助;请看这里:我忘了提到:有一个生成的getter抛出异常-无法触及DBNull值。没有办法更改getter-当然我可以更改它(对于每个空列),但它将被相关对象的每次更改所覆盖。亲爱的微软,你为什么这么做?我认为NULL是TSQL中的一个正常值,而不是“总是抛出愚蠢的无意义异常”的值。我不需要默认值!我需要空值。Null表示我不在输出XML中放入标记,“”和0以及类似的表示我需要放入一个空标记或包含“0”内容的标记。XML模式和规则不是由我定义的,因此我必须为此制定一个非常棘手的解决方案。空值只是整个过程正常运行所必需的。@Harry,我建议修改您的原始问题,以反映您程序的这些附加约束/期望结果(包括您对“生成的getter”的评论)。您肯定是对的。我认为我的问题有点误导。
connstr = @"Data Source=.\sqlexpress;Integrated Security=SSPI;Initial Catalog=Test;";

string sql = "select WidgetId, WidgetName, WidgetValue, CreatedDt, ModifiedDt from dbo.widgets";

using (connection = new SqlConnection(connstr))
{
    connection.Open();
    using (command = new SqlCommand(sql, connection))
    using (IDataReader reader = command.ExecuteReader())
    {
        while (reader.Read())
        {
            Console.Write(reader.GetValue<int>("WidgetId").ToString());
            Console.Write("\t");
            Console.Write(reader.GetValue<string>("WidgetName"));
            Console.Write("\t");
            Console.Write(reader.GetValue<int>("WidgetValue"));
            Console.Write("\t");
            Console.Write(reader.GetValue<DateTime>("CreatedDt"));
            Console.Write("\t");
            Console.Write(reader.GetValue<DateTime>("ModifiedDt"));
            Console.Write("\n");
        }
    }
}
1       Widget 1        0       7/17/2012 6:13:26 AM    1/1/0001 12:00:00 AM
2       Widget 2        0       7/17/2012 6:13:26 AM    1/1/0001 12:00:00 AM
3       Widget 3        0       7/17/2012 6:13:26 AM    1/1/0001 12:00:00 AM
string sql = "select WidgetId, IsNull(WidgetName,""), " +
             "IsNull(WidgetValue,0), CreatedDt, ModifiedDt from dbo.widgets";