views:

220

answers:

3

I have a lambda expression which accepts, a int? (nullable integer),
which returns value if value exists or DBNull.Value otherwise.

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

The goal here is that, I want to make that expression slightly a bit more generic so that I can pass any nullable types like, DateTime?

So here is a non-functional code I was starting off with, but not sure where to specify nullable's type.

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

Is it possible to specify generic type or should I create a named function to do so?

+1  A: 

Instead of using generics, you can just make an extension method on Object to do the conversion.

Here's a sample program. The ToDbObject extension does the conversion:

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();
    } 
}

The above prints:

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

It's correctly handling both cases.

Reed Copsey
+1  A: 

I think you can do it by creating a delegate factory method where you can specify the generic type parameter:

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

And you can use it in your example like this:

SaveImage(
    CreateGetValueFunc<int>()(imageId),
    CreateGetValueFunc<DateTime>()(actionDate));
Lee
If it's being wrapped in a real function, doesn't that moot the point of using a lambda in the first place? The contents of your function might as well be non-lambda code.
John K
Sung Meister
+2  A: 

Since the purpose of the question is to use a lambda expression, here is a solution. It takes a different route by using weak typing instead of the proposed strong typing, but accomplishes the same thing nonetheless.

        // 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

Edit: This loose typing works because the data type of the lambda argument v is of the struct itself and is not the Nullable type wrapper. Apparently the Nullable value that the caller uses has been resolved or 'unwrapped' by the time it hits the lambda argument and the lambda argument reveals a struct value or null; the Nullable wrapper is nowhere to be seen at this point (or as far as I can find). This behaviour can be proved by putting a debug breakpoint in the lambda at v and inspecting its value. The good side effect of this behaviour is the lambda works equally well for both Nullable and non-Nullable types -- it's not restricted.

John K
I have tried this and it works, which was the point of my question. But I have opted out with converting the lambda to a method.
Sung Meister
By the way, this is the first time I have ever used `ReferenceEquals`. Quite refreshing to use actual `Object` method. ;)
Sung Meister