I have made some serious progress since my last post.  I found this very handy extension method, which adds a TryGetValue to SPListItem.

   1: // Credits: http://blog.mastykarz.nl/obtain-fields-values-splistitem/comment-page-1/#comment-11076
   2: internal static bool TryGetValue<T>(this SPListItem listItem, string fieldName, out T value)
   3: {
   4:     value = default(T);
   5:  
   6:     try
   7:     {
   8:         object candidate = listItem[fieldName];
   9:  
  10:         if (candidate == null)
  11:         {
  12:             return false;
  13:         }
  14:         value = (T) candidate;
  15:  
  16:         return true;
  17:     }
  18:     catch 
  19:     {
  20:         return false;
  21:     }
  22: }

The credit goes to Waldek.  While this isn’t earth shattering,  it is proof that tooling up goes a long way in increasing developer productivity.

   1: if (idea.TryGetValue("Title", out title))
   2: {
   3:     ideaTitleLabel.Text = title;
   4: }
   5: else
   6: {
   7:     ThrowMissingFieldException("title");
   8: }

I am building out my own kit of utilities as well.  Here is a utility for generating a DropDownList of all lists in a web:

   1: internal static DropDownList GetWebSpList(string url, Cache cache, CacheOptions cacheOptions)
   2: {
   3:     DropDownList dropDownList;
   4:  
   5:     using (DataSet listsDataSet = GetSpLists(url, cache, cacheOptions))
   6:     {
   7:         dropDownList = new DropDownList();
   8:  
   9:         foreach (DataRow row in listsDataSet.Tables[IPM_LIST_TABLE].Rows)
  10:         {
  11:             ListItem item = new ListItem(row["Title"].ToString(), row["ID"].ToString());
  12:  
  13:             dropDownList.Items.Add(item);
  14:         }
  15:     }
  16:  
  17:     return dropDownList;
  18: }

The method GetSpLists, looks like this:

   1: private static DataSet GetSpLists(string url, Cache cache, CacheOptions cacheOptions)
   2: {
   3:     DataSet listCache = null;
   4:  
   5:     if ((cacheOptions & CacheOptions.ReadFromCache) == CacheOptions.ReadFromCache)
   6:     {
   7:         listCache = cache[IPM_LIST_CACHE] as DataSet;
   8:     }
   9:  
  10:     if (listCache == null || (cacheOptions & CacheOptions.ReadLive) == CacheOptions.ReadLive)
  11:     {
  12:         listCache = CreateListCacheDataSet();
  13:  
  14:         using (SPSite site = new SPSite(url))
  15:         using (SPWeb web = site.OpenWeb())
  16:         {
  17:             SPListCollection lists = web.Lists;
  18:  
  19:             foreach (SPList list in lists)
  20:             {
  21:                 listCache.Tables[IPM_LIST_TABLE].Rows.Add(list.ID, list.Title);
  22:             }
  23:         }
  24:  
  25:         if ((cacheOptions & CacheOptions.AddToCache) == CacheOptions.AddToCache)
  26:         {
  27:             cache.Add(IPM_LIST_CACHE,
  28:                       listCache,
  29:                       null,
  30:                       Cache.NoAbsoluteExpiration,
  31:                       new TimeSpan(0, 0, 30, 0),
  32:                       CacheItemPriority.BelowNormal, null);
  33:             
  34:         }
  35:     }
  36:     return listCache;
  37: }

And CreateListCacheDataSet looks like this:

   1: private static DataSet CreateListCacheDataSet()
   2: {
   3:     DataSet listCache = new DataSet(IPM_LIST_TABLE);
   4:  
   5:     listCache.Tables.Add(IPM_LIST_TABLE);
   6:  
   7:     DataColumn primaryKeyColumn = listCache.Tables[IPM_LIST_TABLE].Columns.Add("ID", typeof(Guid));
   8:  
   9:     listCache.Tables[IPM_LIST_TABLE].PrimaryKey = new[] { primaryKeyColumn };
  10:  
  11:     listCache.Tables[IPM_LIST_TABLE].Columns.Add("Title", typeof(string));
  12:  
  13:     return listCache;
  14: }

And finally, the CacheOptions enum, which drives whether the lists are read from the cache or read live, and drive whether the resultant list is cached or not, looks like this:

   1: [FlagsAttribute]
   2: internal enum CacheOptions
   3: {
   4:     None,
   5:     ReadFromCache,
   6:     AddToCache,
   7:     RemoveFromCache,
   8:     ReadLive
   9: }