views:

7196

answers:

3

I've written a simple SessionItem management class to handle all those pesky null checks and insert a default value if none exists. Here is my GetItem method:

public static T GetItem<T>(string key, Func<T> defaultValue)
{
    if (HttpContext.Current.Session[key] == null)
    {
        HttpContext.Current.Session[key] = defaultValue.Invoke();
    }
    return (T)HttpContext.Current.Session[key];
}

Now, how do I actually use this, passing in the Func<T> as an inline method parameter?

A: 

Why don't you pass the default value directly? What use is the functor?

By the way, defaultValue.Invoke() is quite verbose. It's also possible to just write defaultValue().

Konrad Rudolph
I guess he wants the default value to be evaluated only if needed, e.g. if the default value is expensive to calculate.
OregonGhost
If I pass the default value directly, then if the default is a new object instance I'll be creating that default object every time I call GetItem, regardless of whether it's going to be used or not. Putting into a Func defers the instantiation to only when it's needed.
tags2k
If you are dealing with instantiation, and if you are using the default constructor - then the ": new()" generic constraint might be helpful (I've edited my post to include). The Func<T> approach is useful if using a non-default constructor.
Marc Gravell
You're right with that. On the other hand, the Func<T> approach will be the most flexible. Depends on the needs of the author then.
OregonGhost
+8  A: 

Since that is a func, a lambda would be the simplest way:

Foo foo = GetItem<Foo>("abc", () => new Foo("blah"));

Where [new Foo("blah")] is the func that is invoked as a default.

You could also simplify to:

return ((T)HttpContext.Current.Session[key]) ?? defaultValue();

Where ?? is the null-coalescing operator - if the first arg is non-null, it is returned; otherwise the right hand is evaluated and returned (so defaultValue() isn't invoked unless the item is null).

Finally, if you just want to use the default constructor, then you could add a "new()" constraint:

public static T GetItem<T>(string key)
    where T : new()
{
    return ((T)HttpContext.Current.Session[key]) ?? new T();
}

This is still lazy - the new() is only used if the item was null.

Marc Gravell
The ?? version doesn't set the value in the session.
David Schmitt
A: 
var log = SessionItem.GetItem("logger", () => NullLog.Instance)

Note, than normally you can skip {T} specification in the GetItem{T} call (if Func{T} returns object of the same type)

Rinat Abdullin