h3mm3's blog

Stories from behind the keyboard

  • RSS
  • Twitter

I recently read an interesting MSDN whitepaper about the correct usage of disposable Windows SharePoint Services object. Simply put, handling SharePoint objects without sufficient care can lead to ugly memory leaks.

For instance, one of the subtleties of SharePoint programming best practices is seen in the following sample (taken from the aforementioned article): although the outer object (an SPSite) is correctly instantiated inside an using statement, the dependent objects (i.e. every SPSite siteCollectionInner) wont be disposed when the program exits the using block! (This looks quite scary...)

public static void SPSiteCollectionForEachBestPractice() 
{ 
  string sUrl = "http://spvm"; 

  using (SPSite siteCollectionOuter = new SPSite(sUrl)) 
  {   
    SPWebApplication webApp = siteCollectionOuter.WebApplication; 

    SPSiteCollection siteCollections = webApp.Sites; 

    SPSite siteCollectionInner = null; 

    foreach (siteCollectionInner in siteCollections) 
    {
      Console.WriteLine(siteCollectionInner.Url);
    }
  } // SPSite object siteCollectionOuter.Dispose() automatically called. 
}

This problem can be seen as a specific SharePoint problem, but in this post I mean to describe a solution to the more general question: how you can easily enforce the disposition of object cycled inside a loop. (Of course you can can wrap the inner code with a try..finally statement, and call siteCollectionInner.Dispose() inside the finally block, as illustrated in the whitepaper)
Here is my two cents: an extension method that applies an Action to any element of an IEnumerable<IDisposable> collection, and then dispose it under the hood.

static void DisposingForEach<T>(
IEnumerable<T> collection, Action<T> action) where T:IDisposable 
{
  foreach(var element in collection)
  {
  try
  {
    action(element); 
  }
  finally 
  {
    if (element!=null)
      element.Dispose();
  }
}

Now we can apply the extension method to the sample code. The result looks pretty nice:

public static void SPSiteCollectionForEachBestPractice() 
{ 
  string sUrl = "http://spvm"; 
  using (SPSite siteCollectionOuter = new SPSite(sUrl)) 
  {   
    SPWebApplication webApp = siteCollectionOuter.WebApplication; 

    SPSiteCollection siteCollections = webApp.Sites; 

    SPSite siteCollectionInner = null; 

    siteCollections.DisposingForEach( 
        inner=> Console.WriteLine(inner.Url)};
    }
  } // SPSite object siteCollectionOuter.Dispose() automatically called. 
}

We haven’t affected code readability, code complexity is quite the same and code stability is much higher.

Happy programming!

No comments: