Monday, April 11, 2011

Ex-tension

There is a simple rule of thumb in which namespace extensions methods should be put. If this is a general purpose extension method - put it in the same namespace as 'this' parameter:

namespace System
{
 public static class StringExtensions
 {
  public static string Fmt(this string format, params object[] args)
  {
   return string.Format(format, args);
  }
 }
}

If an extension method use some specific parameters, but still is more or less general purpose, put in into the narrowest namespace of method parameters.

And if the method is specific method, put it in the namespace where it will be used. Also it is good to mark this method as 'internal'.

Wednesday, April 6, 2011

Common LINQ mistakes

  1. Never use
    enumerable.Count() > 0

    Instead use
    enumerable.Any()

    Count() will enumerate entire collection, Any() will stop after first item.
  2. Never ever use
    from x in enumerable
    orderby x.Item1
    orderby x.Item2
    select x;
    
    Your collection will be ordered by x.Item2, not by x.Item1 then by x.Item2. Instead use:
    from x in enumerable
    orderby x.Item1, x.Item2
    select x;
    
    The same is applicable for extensions methods.
    Wrong:
    var ordered = enumerable.OrderBy(x=>x.Item1).OrderBy(x=>x.Item2);
    
    Correct:
    var ordered = enumerable.OrderBy(x=>x.Item1).ThenBy(x=>x.Item2);
    
  3. Do not forget about closures scope.
    foreach (var x in enumerable)
    {
     var some = enumerable2.Where(y => y == x);
     list.Add(some);
    }
    
    As far as x is closed, you probably assume that 'some' will depend on each item from 'enumerable'. But actually, 'x' is defined outside of foreach (due to C# implementation), so all 'some's will be calculated using the last value. To prevent this, either fold all enumerables (in general - all lazy calculations) inside blocks, or use locally scoped variables.
    foreach (var x in enumerable)
    {
     var local = x; 
     var some = enumerable2.Where(y => y == local);
     list.Add(some);
    }
    
    Fortunately, Resharper will not let you forget about this.