型付きDataSetのDataRowからNull許容で値を取得する。(.Net)

#型付データセット
.Net FrameworkではDataSetをデザイナから生成すると、固有の型を持った型付DataSetを使用できるようになる。
ただ、Null許容型の列については、nullを値として返すことはできず、Nullチェックが必須になる。
(.Net 3.5からはDataRow.Field<>メソッドで対応可能）。

* サンプルコード  
型付データセットに設定した  
ID(int,必須),  
Name(string,Null許容),  
Address(string,Null許容),  
年齢(int,Null許容)を  
画面項目に設定しているコードについて考える。

```csharp
            var ds = new SampleDataSet();
            var row = ds.Table[0];
            row.ID = 1;
            row.NAME = "名前";
            row.ADDRESS = null;
            row.SetAGENull();

            labelID.Text = row.ID.ToString();
            if (row.IsNAMENull())
            {
                labelName.Text = string.Empty;
            }
            else
            {
                labelName.Text = row.NAME;
            }

            if (row.IsADDRESSNull())
            {
                labelAddress.Text = string.Empty;
            }
            else
            {
                labelAddress.Text = row.ADDRESS;
            }

            if (row.IsAGENull())
            {
                labelAge.Text = string.Empty;
            }
            else
            {
                labelAge.Text = row.AGE.ToString();
            }

```

* 簡潔に書きたい。  
この程度であればNullチェックせずに代入したくなるが、Nullチェックしないと例外が発生する。
 
```csharp
            var ds = new SampleDataSet();
            var row = (SampleDataSet.TableRow)ds.Table.NewRow();
            row.ID = 1;
            row.NAME = "名前";
            row.ADDRESS = null;
            row.SetAGENull();
            ds.Table.Rows.Add(row);

            labelID.Text = row.ID.ToString();
            labelName.Text = row.NAME;
            // ここでDBNullエラー
            labelAddress.Text = row.ADDRESS;
            labelAge.Text = row.AGE.ToString();
```

* Null許容型にする。
  DataSetはObject型に元の値を格納しているが、nullはDBNullを使用する点を考慮すれば、拡張メソッドでNullableにすることは簡単にできる。  
 * ```csharp
// 拡張メソッド
public static class DataSetExtension
    {
        public static T? GetValue<T>(this DataRow row, DataColumn column) where T : struct
        {
            var value = row[column];
            if (Convert.IsDBNull(value))
            {
                return null;
            }
            else
            {
                return (T)value;
            }
        }

        public static string GetValueString(this DataRow row, DataColumn column)
        {
            var value = row[column];
            if (Convert.IsDBNull(value))
            {
                return null;
            }
            else
            {
                return (string)value;
            }
        }

        public static void SetValue(this DataRow row, DataColumn column, object value)
        {
            if (value == null)
            {
                row[column] = DBNull.Value;
            }
            else
            {
                row[column] = value;
            }
        }
    }

         ```  

  * 最終的なコード  
 作成したGetメソッドとSetメソッド使用するように修正した。

```csharp
            var ds = new SampleDataSet();
            var row = (SampleDataSet.TableRow)ds.Table.NewRow();
            row.ID = 1;
            row.NAME = "名前";
            row.SetValue(ds.Table.ADDRESSColumn, null);
            row.SetValue(ds.Table.AGEColumn, null);
            ds.Table.Rows.Add(row);

            labelID.Text = row.ID.ToString();
            labelName.Text = row.NAME;
            // nullが設定される。
            labelAddress.Text = row.GetValueString(ds.Table.ADDRESSColumn);
            // 空文字が設定される。Nullable型はnullでToStringしても、NullReferenceExceptionは発生しない。
            labelAge.Text = row.GetValue<int>(ds.Table.AGEColumn).ToString();
```
 * .Net 3.5以降  
   DataRow.Field, DataRow.SetField拡張メソッドを使用するだけでよい。

```csharp
            var ds = new SampleDataSet();
            var row = (SampleDataSet.TableRow)ds.Table.NewRow();
            row.ID = 1;
            row.NAME = "名前";
            row.SetField<string>(ds.Table.ADDRESSColumn, null);
            row.SetField<int?>(ds.Table.AGEColumn, null);
            ds.Table.Rows.Add(row);

            labelID.Text = row.ID.ToString();
            labelName.Text = row.NAME;
            labelAddress.Text = row.Field<string>(ds.Table.ADDRESSColumn);
            labelAge.Text = row.Field<int?>(ds.Table.AGEColumn).ToString();
```


[目次](http://qiita.com/csharpisthebest/items/57f27a33085f01211166)