Wednesday, June 29, 2011

Coconut

Simple, but little painful snare regarding Streams and StreamWriters.

Let's imagine we have a function that print some data to a TextWriter:

void Print(TextWriter writer)
{
 // ...
}

Also we have a stream (e.g. Http output stream), which we want to use to print in data. So, we'll write something like:

using (Stream stream = GetOutputStream()){
  var streamWriter = new StreamWriter(stream);
  Print(streamWriter);
}

This code is fair enough - as far as StreamWriter uses the disposed stream, there should not be any resource leaks as far as we're disposing the thread. But there is some bug which can lead to data losses.

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.

Monday, January 17, 2011

How to create generic type

Just a side note.

If you need to create a generic type having only Type object of the generic argument, you could do this (e.g. we need to create List of some objects):

public IEnumerable CreateList(Type elementType, int capacity)
{
    Type listType = typeof(List<>).CreateGenericType(elementType);
    return (IEnumerable)Activator.CreateInstance(listType, capacity);
}

Note, that you cannot return List<T> because you do not actually have compile-time type List<T>. So you need to cast the result of Activator.CreateInstance to some non-generic type.

Saturday, December 25, 2010

Let.It.Be

Just another stupid question, bad for checking knowledge, but good enough to find out one's "tactical" architecture design capabilities.

It's not a secret that C# translates LINQ queries into chain of extension method calls. For instance, the following code snippet:

var entities = from e in list
               where e.Id > 10
               select e.Name;

will be transcribed as

var entities = list.Where(e=>e.Id > 10).Select(e=>e.Name);

But how is 'let' keyword transcribed? There is no .Let() method in LINQ. Could you suggest your solution?

Friday, November 19, 2010

Commutativity and LINQ

Yet another stupid questions. Imagine, you have defined a class:

class Entity{
 public int Id { get; set; }
 public int Priority { get; set; }
}

And also you have some sequence of Entity objects (i.e. IEnumerable entities). You need to group entities by its Id and select only entities with priority greater than 5.

As far as "and" is commutative and according to the task the following two blocks of code should return the same result


var group1 = entities.Where(e=>e.Priority > 5).GroupBy(e=>e.Id);
and
var group2 = entities.GroupBy(e=>e.Id).Select(g=>g.Where(e=>e.Priority > 5));

But this is wrong. There are two different sets of input data that will produce to different results (by two different reasons). Could you find them out?

Monday, November 1, 2010

Why IEnumerator<T> is IDisposable

Recently I've posted that IEnumerator<T> is IDisposable, but had not explained, why it is.

The explanation is rather simple - because of "yield return". Let's track this down.