4

このジェネリックメソッドを使用してDataRowオブジェクトを拡張しようとしています。

public static T? Get<T>(this DataRow row, string field) where T : struct
{
  if (row.IsNull(field))
    return default(T);
  else
    return (T)row[field];
}

Tが、、、などの場合は正常に動作intdecimalますdouble

しかし、文字列で使用しようとすると、次のエラーが発生します:

「タイプ'string'は、ジェネリック型またはメソッド'System.Nullable'のパラメーター'T'として使用するために、null許容値ではないタイプである必要があります。」

どうすればこれを修正できますか?

文字列が構造体ではないことは知っていますが、文字列フィールドがDBNullの場合はnullを返しません。

4

7 に答える 7

6

私はこれがあなたが望むものだと思います:

public static T? GetValue<T>(this DataRow row, string field) where T : struct
{
    if (row.IsNull(field))
        return new T?();
    else
        return (T?)row[field];
}

public static T GetReference<T>(this DataRow row, string field) where T : class
{
    if (row.IsNull(field))
        return default(T);
    else
        return (T)row[field];
}
于 2011-02-09T17:08:28.247 に答える
5

stringではなくstructclassです。これがエラーメッセージの内容です。制約を削除するだけです。

たぶん、 DataRowExtensionsを見てみたいと思うでしょう。

于 2011-02-09T16:53:19.813 に答える
2
ds.Tables[7].Rows.OfType<DataRow>().ToList().ForEach(f => tempList.Add(new MyEntity
{
  Id = int.Parse(f.ItemArray[0].ToString()),
  Title = f.ItemArray[1].ToString()
 }));
于 2011-06-24T14:59:16.653 に答える
2

残念ながら、呼び出し時にNullableを返すように指定しない限り、ジェネリックを使用してNullable戻り型と参照型のサポートを取得することはできません。

public static T Get<T>(this DataRow row, string field)
{
    if (row.IsNull(field))
        return default(T);
    else
        return (T)row[field];
}

そしてあなたが電話するとき

var id = dr.Get<int?>("user_id");

私はこれをテストしませんでした、ただここにそれを投げました。試してみます。

編集:

あるいは、値型をnull可能に変換し、それでも参照型をサポートできるようにしたい場合は、このようなものが機能する可能性があります

public static object GetDr<T>(this DataRow row, string field)
{
    // might want to throw some type checking to make 
    // sure row[field] is the same type as T
    if (typeof(T).IsValueType)
    {
        Type nullableType = typeof(Nullable<>).MakeGenericType(typeof(T));
        if (row.IsNull(field))
            return Activator.CreateInstance(nullableType);
        else
            return Activator.CreateInstance(nullableType, new[] { row[field] });
    }
    else
    {
        return row[field];
    }
}

ただし、使用するたびにキャストが必要になります

var id = dr.Get<string>("username") as string;
var id = (int?)dr.Get<int>("user_id");

ただし、これは、ジェネリック型パラメーターでnull許容型を受け入れるほど効率的ではありません。

于 2011-02-09T16:58:06.693 に答える
1

Wesが指摘しているように、あなたの問題は構造化の制約です。拡張メソッドが制約なしで機能することを期待しています...

ああ、わかりました、あなたは戻ってきています。よくわかりませんが、1つはに制約し、もう1つはに制約して返すT?メソッドの2つのバリアントを定義できますか?structclassT

于 2011-02-09T16:48:52.820 に答える
1

これが文字列で機能しないようにする明示的な条件があります。

 where T : struct

System.Stringはクラスであり、構造体ではありません。値の型と文字列を処理することが目標の場合は、文字列用に別のメソッドを作成し、他の型にはこれをそのままにしておきます。

于 2011-02-09T16:53:27.390 に答える
1

このようなものはどうですか?例とはまったく同じではありませんが、参照型、null許容値型、およびnull許容でない値型に同様に使用できます。

int v = row.Get<int>("vvv");               // throws if column is null
int? w = row.Get<int?>("www");             // set to null if column is null
int x = row.Get<int?>("xxx") ?? -1;        // set to -1 if column is null
string y = row.Get<string>("yyy");         // set to null if column is null
string z = row.Get<string>("zzz") ?? ""    // set to "" if column is null

// ...

public static T Get<T>(this DataRow source, string columnName)
{
    if (source == null)
        throw new ArgumentNullException("source");

    if (columnName == null)
        throw new ArgumentNullException("columnName");

    if (columnName.Length < 1)
        throw new ArgumentException("Name cannot be empty.", "columnName");

    if (source.IsNull(columnName))
    {
        T defaultValue = default(T);
        if (defaultValue == null)
            return defaultValue;
    }

    // throws if the column is null and T is a non-nullable value type
    return (T)source[columnName];
}
于 2011-02-09T16:59:28.837 に答える