Как передать параметр Generic Type в лямбда-выражение? - PullRequest
3 голосов
/ 24 октября 2009

У меня есть лямбда-выражение, которое принимает, int? (обнуляемое целое число),
который возвращает значение, если значение существует, или DBNull.Value в противном случае.

Func<int?, object> getId = id => id.HasValue ? id.Value : (object)DBNull.Value;

Цель в том, чтобы я хотел сделать это выражение немного более общим, чтобы я мог передавать любые типы, допускающие обнуление, такие как, DateTime?

Итак, вот нефункциональный код, с которого я начинал, но не уверен, где , чтобы указать тип Nullable .

int? imageId;
DateTime? actionDate;
Func<Nullable<T>, object> getValue = 
    id => id.HasValue ? id.Value : (object) DBNull.Value;
SaveImage(getValue(imageId), getValue(actionDate));

Можно ли указать универсальный тип или я должен создать именованную функцию для этого?

Ответы [ 3 ]

3 голосов
/ 24 октября 2009

Поскольку целью вопроса является использование лямбда-выражения, здесь есть решение. Он использует другой путь, используя слабую типизацию вместо предложенной строгой, но тем не менее выполняет то же самое.

        // A lambda solution
        Func<object, object> fnGetValue =
            v =>
                ReferenceEquals(v, null)
                ? DBNull.Value
                : v;


        // Sample usage
        int? one = 1;
        int? two = null;
        object o1 = fnGetValue(one); // gets 1
        object o2 = fnGetValue(two); // gets DBNull

Редактировать : Эта произвольная типизация работает, поскольку тип данных лямбда-аргумента v относится к самой структуре и не является оболочкой типа Nullable. Очевидно, значение Nullable, которое использует вызывающая сторона, было разрешено или «развернуто» к тому времени, когда оно достигает аргумента lambda, а аргумент lambda раскрывает значение struct или null; Nullable обертка нигде не видно (или, насколько я могу найти). Такое поведение можно доказать, поместив точку останова отладки в лямбду в v и проверив ее значение. Хорошим побочным эффектом этого поведения является то, что лямбда работает одинаково хорошо как для Nullable, так и для Nullable типов - это не ограничено.

1 голос
/ 24 октября 2009

Я думаю, вы можете сделать это, создав метод фабрики делегатов, в котором вы можете указать параметр общего типа:

public static Func<Nullable<T>, object> CreateGetValueFunc<T>() where T : struct
{
    return id => id.HasValue ? id.Value : (object)DBNull.Value;
}

И вы можете использовать его в своем примере следующим образом:

SaveImage(
    CreateGetValueFunc<int>()(imageId),
    CreateGetValueFunc<DateTime>()(actionDate));
1 голос
/ 24 октября 2009

Вместо использования обобщений вы можете просто создать метод расширения для Object, чтобы выполнить преобразование.

Вот пример программы. Расширение ToDbObject выполняет преобразование:

using System;

static class Program
{
    static object ToDbObject(this object value)
    {
        return value ?? DBNull.Value;
    }
    static void Main(string[] args)
    {
        int? imageId = 3; 
        DateTime? actionDate = null;

        Console.WriteLine("ImageId {0}: [{1}] - {2}", imageId, imageId.ToDbObject(), imageId.ToDbObject().GetType());
        Console.WriteLine("actionDate {0}: [{1}] - {2}", actionDate, actionDate.ToDbObject(), actionDate.ToDbObject().GetType());
        Console.ReadKey();
    } 
}

Вышеуказанные отпечатки:

ImageId 3: [3] - System.Int32
actionDate : [] - System.DBNull

Он правильно обрабатывает оба случая.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...