вторник, 2 декабря 2008 г.

LINQ to Objects. VS2008 SP1 Bug!

Не так давно, работая над одним проектом столкнулся с проблемой. Начало выпадать исключение в уже проверенном коде. Проковырявшись с отладчиком с полчаса я нашел место возникновения ошибки: var bytes = Enumerable.Range(1, 5).Select(i => (byte)i); Данный оператор валился с исключением InvalidCastException. Особенно грустно было то, что я этот код проверял и тестировал и никаких ошибок не было. Да и не может здесь быть никаких InvalidCast-ов, т.к. я руками спокойно могу преобразовать int-ы в диапазоне от 1 до 5 к byte-у. Попробовав еще раз проверить этот код за домашним компьютером, я понял в чем причина! Причина в установленном SP1 к Visual Studio 2008. Приведу более полный фрагмент кода: namespace TestLINQ {

class Program

{

static void A()

{

var bytes = Enumerable.Range(1, 5).Select(i => (byte)i);

foreach (var b in bytes)

{

Console.WriteLine(b);

}

}

static void B()

{

var bytes = Enumerable.Range(1, 5).Cast<byte>();

foreach (var b in bytes)

{

Console.WriteLine(b);

}

}

static void Main(string[] args)

{

A();

B();

}

}

}

Функция А() выполняется нормально и, как и ожидается, выводит цифры в диапазоне от 1 до 5, а вот функция B() вываливается с InvalidCastException.

Причем такое поведение наблюдается только после установки SP1 для VS2008, без оного все прекрасно работает!

Кстати, эта ошибка уже всплывала в Visual Studio 2008 Beta 2 (здесь) и вот появилась снова!

1 комментарий:

  1. Как оказалось, это не ошибка, это фича. А ошибкой было то, что этот код работал в Visual Studio 2008 без SP1.
    Более подробно здесь http://blogs.msdn.com/dinesh.kulkarni/archive/2008/08/10/net-fx-3-5-sp1-two-perf-improvements-linq-to-objects-and-linq-to-sql.aspx и здесь http://blogs.msdn.com/ed_maurer/archive/2008/02/16/breaking-change-in-linq-queries-using-explicitly-typed-range-variables.aspx.
    Если кратко, то вот:
    Cast<T> breaking change: This is a bug fix and a breaking change (see this post for background). The intended use of the NET FX 3.5 Cast<T> extension method is querying over non-generic collection types, whose elements require either a reference conversion or an unboxing step to be used in a generic query context. A late change VS 2008 cycle allowed the cast to succeed in more situations than intended, such as converting float values to int, where it should instead be throwing an InvalidCastException. The breaking change reverts the beta2 behavior and improves perf by simplifying the implementation of CastIterator<T>. Value conversions and explicitly-defined user conversions cause an InvalidCastException instead of being allowed

    ОтветитьУдалить