Забезпечення зворотної сумісності .NET-додатків при використанні WinRT

Створення Windows Runtime (WinRT) в якості API, з одного боку, можна тільки вітати, так як попередній — WinAPI — особливою простотою і людяністю не відрізнявся. З іншого боку, в повний зріст при цьому виникає проблема зворотної сумісності. Що робити, якщо потрібно заиспользовать якусь приємну дрібницю, що з'явилася в Win8, але при цьому не втрачати сумісності з Win7, все ще бадьоро крокує в строю?

Офіційний MSDN до цього ставиться досить однозначно: якщо потрібен WinRT, то забуваємо про версії Windows, старше вісімки; якщо потрібно підтримувати всяке лахміття, то збираємо додаток окремо без згадки про WinRT. Такі от прості і невигадливі хлопці працюють в Microsoft. Тим не менш, рішення проблеми, причому досить просте, вдалося відшукати.

Суть в тому, що ми можемо всю потрібну для щастя імплементацію, що вимагає WinRT, віднести в окрему збірку, і в разі необхідності намагатися довантажити її динамічно: вдається — чудово, ну а не виходить — смиряємось і підсовуємо заглушку з тим же інтерфейсом.

Припустимо, у нас виникло бажання, користуючись WinRT, читати значення датчика освітленості ноутбука/планшету. За це відповідає клас LightSensor з простору імен Windows.Devices.Sensors. В такому випадку діаграму класів можна представити наступним чином:
image

Interfaces — самий звичайний Class Library, що містить інтерфейс IWinRTAccessor, повертає своїм єдиним методом GetLightValue рівно те, що нам потрібно, а саме рівень освітленості в разі наявності сенсора і null у разі його відсутності. Там же оголошена заглушка FakeWinRTAccessor, що реалізує цей інтерфейс, завжди повертає null. Крім того, тут же розташований клас WinRTAccessorFactory, чий фабричний метод инстанцирует потрібну реалізацію IWinRTAccessor. Найпримітивніша реалізація цього фабричного методу виглядає так:
public static IWinRTAccessor GetAccessor()
{
if (_winRtAccessor == null)
{
try
{
String path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), WinRTAccessorAssemblyName);
Assembly assembly = Assembly.LoadFile(path);
Type type = assembly.GetTypes().First(t => t.GetInterface(typeof (IWinRTAccessor).Name) != null);
_winRtAccessor = (IWinRTAccessor) Activator.CreateInstance(type);
}
catch
{
_winRtAccessor = new FakeWinRTAccessor();
}
}
return _winRtAccessor;
}


WinRTLib — не менш звичайний Class Library (на ім'я якого і вказує константа WinRTAccessorAssemblyName), в якому зосереджена логіка роботи з WinRT, однак для його підтримки потрібно піти на невелику хитрість: прописати у файлі проекту.csproj) наступний Property Group:

<PropertyGroup>
<targetplatformversion>8.0</targetplatformversion>
</PropertyGroup>

І вже тільки після цього додавати Windows Core References. Нас у даному випадку цікавить Windows.Devices:


Сам метод, извлекающий показання датчика освітленості, спасибі новому API, досить простий:
public Single? GetLightValue()
{
LightSensor light = LightSensor.GetDefault();

if (light != null)
return light.GetCurrentReading().IlluminanceInLux;

return null;
}


В принципі, цього б вистачило, якщо не відкладена компіляція: в більш ранніх версіях Windows ця збірка має всі шанси коректно завантажитися і инстанцировать примірник RealWinRTAccessor, а впасти вже на виклик методу при зверненні до WinRT. Щоб цього не сталося, смикнемо WinRT прямо в конструкторі:
public RealWinRTAccessor()
{
LightSensor.GetDefault();
}


Тепер, коли потрібно отримати показання датчика освітленості, можна смикати:
WinRTAccessorFactory.GetAccessor().GetLightValue()


Цей код відпрацює як при наявності WinRT, так і для більш ранніх версій Windows — в цьому випадку результатом виклику GetLightValue буде null.

З переваг даного підходу: досягнення поставленої мети і відносна простота.
З недоліків: необхідність наявності прав на завантаження збірок через Assembly.LoadFile, ручна перевірка (її тут немає, але повинна бути) оригінальності подгружаемой складання, ручне керування складанням і місцем розташування WinRTLib, оскільки вона не є Reference кого б то не було.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.