вторник, 3 сентября 2013 г.

.NET 4.5 — обновление на месте .NET 4.0

Вместе с бета версиями VS 2011 и Windows 8 многие люди будут устанавливать, и разбираться с .NET 4.5. В .NET 4.5 добавлено много новых усовершенствований, которые являются достаточно прозрачными, но важно понять, как с точки зрения CLR она работает на вашей машине.

Когда .NET 4.5 устанавливается она, фактически, заменяет .NET 4.0 на вашей машине. .NET 4.0 перезаписывается новой версией .NET 4.5, что в соответствии со словами Microsoft гарантирует 100%-ую совместимость. 100% совместимость звучит привлекательно, но все мы знаем, что добиться такого результата достаточно сложно. Но есть вещь гораздо более интересная, чем обратная совместимость, которая делает ситуацию с разворачиванием .NET 4.5 неудобной в лучшем и запутанной в худшем случае.

Что значит обновление на месте?

Когда Вы устанавливаете .NET 4.5 ваши сборки из .NET 4.0 в папке \Windows\.NET Framework\V4.0.30319 перезаписываются новым набором. В итоге Вы остаетесь с перезаписанными сборками, а так же с кучей новых (например, сборка System.Net.Http). Следующее изображение показывает сборку System.dll для .NET 4.5 (слева) и для .NET 4.0 (справа):



Очевидно, что это разные файлы с разными размерами (интересно, что версия .NET 4.5 меньше размером).

Это еще не все. Если во время выполнения приложения, с установленной .NET 4.5, Вы обратитесь к свойству Environment.Version, то все еще получите 4.0.30319.

Если вы откроете окно свойств сборки System.dll в .NET 4.5 Вы так же увидите



Обратите внимание, что версия файла по-прежнему 4.0.xxx.

Разница в номере компоновки: в .NET 4.0 он равен 261, в то время как в текущей бета версии .NET 4.5 он равен 17379. Я думаю, Вы можете использовать номер компоновки, чтобы определить версию .NET: если он больше чем 17000, то это .NET 4.5, однако, это не очень красивое решение согласитесь.

Не существует простого или очевидного способа, чтобы определить какая из версий .NET 4.5 или .NET 4.0 используется, так как для приложения они являются одинаковыми.

Компилировать для .NET 4.5, а запускать на .NET 4.0 мысль не из хороших


Вы можете компилировать приложение под .NET 4.5 и запускать его под .NET 4.0 до тех пор, пока вы не выходите за рамки функционала доступного только в .NET 4.0. В этот момент приложение просто упадет с ошибкой. Скажем, ваш код в основном использует возможности .NET 4.0, но есть несколько мест, глубоко спрятанных в приложении, в которых используются новые возможности .NET 4.5, например, async/await. .NET с радостью запустит ваше приложение и выполнит успешно весь код, до тех пор, пока не встретит код использующий возможности .NET 4.5, а затем благополучно упадет. Какая радость!

Вы естественно можете запускать приложения, написанные для .NET 4.0 на .NET 4.5 и это должно работать без особых причуд.

Определение версий


Если вы пишете приложение для .NET 4.5, у Вас есть некоторый контроль, над его выполнением, используя конфигурационный файл. Вы можете указать, что приложению необходима .NET 4.5, например, так:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework, Version=v4.5" />
  </startup>
</configuration>
Это делается для того, чтобы приложение при запуске не на .NET 4.5 сообщило об ошибке, вместо падения во время выполнения.

Также веб-приложения на .NET 4.5 могут использовать свойство targetFramework для достижения аналогичных результатов.
<configuration>
  <system.web>
    <compilation debug="true"
                 strict="false"
                 explicit="true"
                 targetFramework="4.5" />
  </system.web>
</configuration>
Это хорошо работает для отдельных настольных и веб приложений, но нет никакого способа для сборок, добавляемых в проект. Для проекта на .NET 4.0 сборка .NET 4.5 выглядит, как и любая другая .NET 4.0 сборка.

Для разработчиков, особенно разработчиков компонентов это особенно проблематично, поскольку нет способа позволяющего определить версию .NET, так как свойство Environment.Version возвращает 4.

Следующий код выводит
void  Main()
{
    Environment.Version.ToString().Dump();
    Environment.Version.Build.Dump();
    Environment.Version.Revision.Dump();
    Environment.Version.Major.Dump();    
}
на .NET 4.0 
4.0.30319.269
30319
269
4

на .NET 4.5 
4.0.30319.17379
30319
17379
4

Довольно, похоже, нет? Заметим, однако, что номер ревизии больше в .NET 4.5 — 17379, в то время как в .NET 4.0 — 261. Если вы действительно хотите знать, что вы используете .NET 4.5 или .NET 4.0 вы можете использовать следующий код:
public static bool IsDotNet45()
{
    return Environment.Version.Major == 4 && Environment.Version.Revision > 17000;
}
Второй способ заключается в попытке обнаружения некоторого типа добавленного в .NET 4.5 с помощью рефлексии.
public static bool IsNet45OrNewer()
{
    // Класс "ReflectionContext" доступен начиная с .NET 4.5.
    return Type.GetType("System.Reflection.ReflectionContext", false) != null;
}
Одним из преимуществ данного подхода является возможность использования в более поздних версиях .NET. 

Тем не менее, достаточно показательно, что нам приходится прибегать к такого рода уловкам, чтобы просто выяснить совместимость версий.

Различие с .NET 3.0 / 3.5


Учтите, что это обновление на месте сильно отличается от обновления .NET 2.0 до .NET 3.0 / 3.5 (так же было на месте), которые работали на CLR второй версии. Обе 3.x версии были просто библиотечными усовершенствованиями поверх ядра .NET 2.0. Обе версии работали под управлением .NET 2.0, который не был изменен на протяжении всего цикла 3.x. В свою очередь, обновление под номером 4.5 полностью заменяет .NET 4.0 оставляя фактический номер версии v4.0.30319.

Когда вы создаете новый проект в VS 2011, вы все еще можете выбрать версию платформы .NET 4.0 или .NET 4.5. Но фактически вы ссылаетесь на один и тот же набор сборок независимо от выбранной вами версии. Разница заключается в том, что при компилировании под .NET 4.0 компилятор дает лишь подмножество возможностей доступных в NET 4.0, но при компилировании под .NET 4.5 вы можете использовать всю функциональность. Это вовсе не означает, что вы можете использовать VS 2010 для разработки приложений под .NET 4.5.

Хорошие новости — плохие новости


Microsoft старается экспериментировать всеми возможными способами разворачивания новых версий .NET. Не существует двух обновлений, которые были бы одинаковыми. Конечно полное обновление (такое как .NET 2.0, 4.0) имеет свои недостатки, но делать обновление на месте и при этом не обеспечивать даже способа определения текущей версии .NET не совсем правильно, даже по стандартам Microsoft. Особенно учитывая, что .NET 4.5 является достаточно большим обновлением со всеми async-ами. Большинство API использующее IO было обновлено для поддержки async-ов, что существенно повлияло на существующее API. Что еще хуже .NET 4.5 будет поставляться вместе с Windows 8, так что будет с нами в течение еще длительного времени, если конечно Microsoft не примет, наконец, решение об обновлении версии .NET в рамках обновления системы. Точно так же было с Vista, которая поставлялась с промежуточной версией .NET 3.0, которая была быстро заменена на более практичную и долгоживущую .NET 3.5. Людям хватило проблем с запутанной ситуацией с 3.x версиями, которые работали фактически на .NET 2.0. Я даже не могу сосчитать количество заданных вопросов о том, что люди не могут найти .NET 3.5 в диалоговом окне IIS. Тоже самое может произойти с .NET 4.5. Хорошо когда мы знаем способ обновления до версии 4.5, но администраторы не до конца знакомые с .NET вряд ли поймут эти нюансы, и в конечном итоге будут путаться какая версия .NET установлена.

Мне трудно увидеть преимущество в таком способе обновления, я даже не видел внятного объяснения, почему был выбран именно такой подход. Конечно, при таком подходе существующие привязки к сборкам не ломаются, так что приложение может оставаться работающим после обновления. Я думаю, это может оказаться полезным для некоторых поставщиков компонентов. А если серьезно, вы действительно собираетесь смешивать .NET 4.0 и .NET 4.5 (не перекомпилировав приложение), а затем всё тщательно протестировать, чтобы убедиться что все работает? Перекомпиляция не кажется чем-то серьезным в свете прозрачного обновления версии.

Комментариев нет:

Отправить комментарий