Vish
Vish

Reputation: 473

Assign variable to result of lambda expression

I'd like to accomplish something like the following:

(clientSinceChoices =  Enumerable.Range(1949, DateTime.Now.Year - 1950)
    .Select(x => new SelectListItem() 
    { 
        Text = x != 1949 ? x.ToString() : "Unselected", 
        Value = x != 1949 ? new DateTime(x, 1, 1).ToString() : null,
        Selected = () => 
        {
            if (x == 1949 && !ClientSinceYearOnly.HasValue)
                return true;
            else if (ClientSinceYearOnly.Value == x)
                return true;
            else
                return false;
        }
    }));

I want the value of Selected to be the result of the labmda expression that is defined inline. I know I can accomplish this by assigning the lambda to a variable and then invoking it, but I think that defining and immediately invoking it is "cleaner".

Upvotes: 3

Views: 6236

Answers (4)

Eric Lippert
Eric Lippert

Reputation: 659994

First off, to actually answer your question: you can invoke a lambda "in place" by casting it to a delegate:

bool x = ((Func<bool>) ()=>true) ();

But in your code there is no need for the lambda in the first place; I don't see why you have a lambda at all. You want to compute a Boolean, so compute the Boolean:

Selected = (x == 1949 && !ClientSinceYearOnly.HasValue) || 
                         (ClientSinceYearOnly.Value == x)

(Also, note that you do not have to check to see if the nullable has a value before you compare it; equality is "lifted to nullable" in C#.)

Second, this query is a mess because you've got a special case in there. I would not write your query like this in the first place. I would rather say:

var choices = new List<Item>();
choices.Add(new SelectListItem()
{
    Text = "Unselected",
    Value = null;
    Selected = ClientSinceYearsOnly == null
};

choices.AddRange(
    Enumerable.Range(1950, DateTime.Now.Year - 1951)
    .Select(x => new SelectListItem() 
    { 
        Text = x.ToString(), 
        Value = new DateTime(x, 1, 1).ToString(),
        Selected = x == ClientSinceYearOnly
    });

Much clearer. Or, write yourself an extension method that sticks something onto the start of a sequence:

public static IEnumerable<T> Prepend<T>(this IEnumerable<T> sequence, T first)
{
    yield return first;
    foreach(T item in sequence) 
        yield return item;
}

and then:

var choices = 
    Enumerable.Range(1950, DateTime.Now.Year - 1951)
    .Select(x => new SelectListItem() 
    { 
        Text = x.ToString(), 
        Value = new DateTime(x, 1, 1).ToString(),
        Selected = x == ClientSinceYearOnly
    })
    .Prepend(new SelectListItem()
    {
        Text = "Unselected",
        Value = null;
        Selected = ClientSinceYearsOnly == null
    });

Upvotes: 10

Gabe
Gabe

Reputation: 86708

This isn't the best use for a lambda, but the way you invoke a lambda inline is just by putting parentheses after it:

(clientSinceChoices =  Enumerable.Range(1949, DateTime.Now.Year - 1950)
    .Select(x => new SelectListItem() 
    { 
        Text = x != 1949 ? x.ToString() : "Unselected", 
        Value = x != 1949 ? new DateTime(x, 1, 1).ToString() : null,
        Selected = ((Func<bool>)(() => 
        {
            if (x == 1949 && !ClientSinceYearOnly.HasValue)
                return true;
            else if (ClientSinceYearOnly.Value == x)
                return true;
            else
                return false;
        }))() // <-- the () calls the function
    }));

Upvotes: 1

Douglas
Douglas

Reputation: 54877

The following code is functionally equivalent:

Selected = 
    x == 1949 && !ClientSinceYearOnly.HasValue ||
    ClientSinceYearOnly.Value == x;

Upvotes: 0

Platinum Azure
Platinum Azure

Reputation: 46183

You could always put the conditional in a method and invoke that:

public static bool ShouldBeSelected(int x)
{
    if (x == 1949 && !ClientSinceYearOnly.HasValue)
        return true;
    else if (ClientSinceYearOnly.Value == x)
        return true;
    else
        return false;
}

Then you can just use it:

        (clientSinceChoices =  Enumerable.Range(1949, DateTime.Now.Year - 1950)
                                        .Select(x => new SelectListItem() 
                                        { 
                                            Text = x != 1949 ? x.ToString() : "Unselected", 
                                            Value = x != 1949 ? new DateTime(x, 1, 1).ToString() : null,
                                            Selected = ShouldBeSelected(x)
                                        }));

Also, in your case, you could use a series of logical operators since you're returning a boolean (not recommended if you don't want the future maintainers to kill you in your sleep):

(x == 1949 && !ClientSinceYearOnly.HasValue) || (ClientSinceYearOnly.Value == x)

Upvotes: 5

Related Questions