If you’re waiting for part 2 of the TFS FTP stuff don’t worry its coming, I’m just waiting on an install by our tech guys so I can finish testing on it.

Following on from the little extension method I posted yesterday which used Action<T> I started thinking of the many uses I’ve found for Action and Func. Cue a mini-series of posts on easy tricks you can do with them! First up – using generics and Func to reduce endless lines of viewstate and session code.

Firstly, if you are using code like this:

public void DoSomething()
{
  DateTime lastActivity = DateTime.Now;

  if (Session["LastActivity"] != null)
    lastActivity = (DateTime) Session["LastActivlity"];

  MyLabel.Text = "Last used: " + lastActivity.ToShortDateString();
}

You are doing it wrong! Littering your code with calls to session is not only asking for runtime errors (noticed the bug in the code above?) but makes it really awkward to swap out your mechanism – if you wanted to switch to SQL server persistence say, you would have to change every single reference - urgh!

So wrap it in a property, which is sat somewhere all code which requires it can see it, maybe a base Page class or your masterpage:

public DateTime LastActivity
{
  get
  {
    if (Session["LastActivity"] == null)
      Session["LastActivity"] = DateTime.Now;
    return (DateTime) Session["LastActivity"];
  }
  set { Session["LastActivity"] = value; }
}

public void DoSomething()
{
  MyLabel.Text = "Last used: " + LastActivity.ToShortDateString();
}

Nice, its all type-safe and your DoSomething code is clearer in intent. You will find though that you soon end up with loads of these properties defined in a row - I designed this helper after opening a file with 30 of them in it! I’ve therefore designed a little bit of code to simplify defining the property:

public T GetSession<T>(string item, Func<T> defaultValue)
{
  if (Session[item] == null)
    Session[item] = defaultValue();
  return (T)Session[item];
}

You can then define your property like this:

public DateTime LastActivity
{
  get { return GetSession("LastActivity", () => DateTime.Now); }
  set { Session["LastActivity"] = value; }
}

How does it work? Well you could have written the call as GetSession<DateTime>(“LastActivity”, () => DateTime.Now) which will make things clearer. We’re using the generic type T – in this case a DateTime and checking to see if the Session contains one. If not we set the session to the result of a function which returns a DateTime. We didn’t define the DateTime type in our above code because the framework is smart enough to figure it out from the return type of the Func argument.

You might be wondering why we didn’t just define GetSession as T GetSession<T>(string item, T defaultValue). The benefit of using Func is that it will only get run when the session is empty. If we were to just pass T, that would be populated into memory every time you called your property, this is not much of an issue here, but would be a huge performance drain if you were accessing a datastore or the like:

return GetSession(“LastActivity”, SqlDatabase.Users(CurrentUser.Name).LastActivity)

You can also of course do exactly the same with the ViewState:

protected T GetViewState<T>(string item, Func<T> defaultValue)
{
  if (ViewState[item] == null)
    ViewState[item] = defaultValue();
  return (T)ViewState[item];
}
Happy coding!