средство получения универсального поля для DataRow - PullRequest
4 голосов
/ 09 февраля 2011

Я пытаюсь расширить объект 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 int, decimal, double и т. Д.

Но когда я пытаюсь использовать строку, у меня появляется эта ошибка:

"Тип 'строка' должен быть необнуляемый тип значения для того, чтобы используйте его как параметр 'T' в общем тип или метод 'System.Nullable' "

Как я могу это исправить?

Я знаю, что строка не является структурой, но я не хочу возвращать ноль, если строковое поле - DBNull.

Ответы [ 7 ]

6 голосов
/ 09 февраля 2011

Я думаю, что это то, что вы хотите:

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];
}
5 голосов
/ 09 февраля 2011

string - это не struct, а class.Это то, что говорит вам сообщение об ошибке.Просто удалите ограничение.

Может быть, вы хотите взглянуть на DataRowExtensions .

2 голосов
/ 24 июня 2011
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()
 }));
2 голосов
/ 09 февраля 2011

К сожалению, вы не сможете получить возвращаемый тип 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");

Я не проверял это, просто бросил здесь. Дайте ему шанс.

EDIT:

В качестве альтернативы, если вы действительно хотите преобразовать типы значений в обнуляемые значения и при этом иметь возможность поддерживать ссылочные типы, что-то подобное может сработать

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");

Это, однако, не будет столь же эффективным, как просто принятие обнуляемого типа в параметрах универсального типа.

1 голос
/ 09 февраля 2011

Как насчет этого?Не совсем так, как в вашем примере, но довольно пригодный для использования со ссылочными типами, типами значений, допускающими значения 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];
}
1 голос
/ 09 февраля 2011

У вас есть явное условие, которое не позволяет работать со строкой:

 where T : struct

System.String это класс, а не структура. Если ваша цель - обрабатывать типы значений и строки, я бы создал отдельный метод для строки и оставил бы это в покое для других типов.

1 голос
/ 09 февраля 2011

Как указывает Уэс, ваша проблема заключается в ограничении структуры. Я ожидаю, что этот метод расширения будет работать без ограничений ...

Ах, теперь я вижу, вы возвращаете T? Ну, я не уверен, но вы можете определить два варианта метода: один ограничивается struct, другой - class и возвращает T?

...