9

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?

tags2k
  • 82,117
  • 31
  • 79
  • 106

3 Answers3

16

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
  • 1,026,079
  • 266
  • 2,566
  • 2,900
2

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
  • 530,221
  • 131
  • 937
  • 1,214
  • I guess he wants the default value to be evaluated only if needed, e.g. if the default value is expensive to calculate. – OregonGhost Oct 01 '08 at 09:05
  • 1
    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 Oct 01 '08 at 09:06
  • 1
    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 approach is useful if using a non-default constructor. – Marc Gravell Oct 01 '08 at 09:13
  • You're right with that. On the other hand, the Func approach will be the most flexible. Depends on the needs of the author then. – OregonGhost Oct 01 '08 at 09:18
1
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
  • 23,036
  • 8
  • 57
  • 80