Создание компонентов среды выполнения Windows в C# и Visual Basic
.NET Framework 4.5 позволяет с помощью управляемого кода создавать собственные типы Среда выполнения Windows, упакованные в компонент Среда выполнения Windows. Этот компонент можно использовать в приложениях Магазина Windows, написанных на C++, JavaScript, Visual Basic или C#. В данной статье описываются правила создания компонента и рассматриваются некоторые аспекты поддержки Среда выполнения Windows в .NET Framework. Как правило, такая поддержка разрабатывается таким образом, чтобы быть прозрачной для разработчиков .NET Framework. Однако при создании компонента, использующего JavaScript или C++, следует учитывать различия в том, как эти языки поддерживают Среда выполнения Windows.
Примечание
Если создается компонент для использования только в приложениях Магазина Windows с Visual Basic или C#, и компонент не содержит элементов управления Магазина Windows, следует использовать шаблон Библиотека классов (приложения для Магазина Windows) вместо шаблона Компонент Среда выполнения Windows. У простой библиотеки классов меньше ограничений.
Данная статья включает следующие разделы.
Объявление типов в компонентах среды выполнения Windows
Отладка компонента
Передача типов среды выполнения Windows в управляемый код
Передача управляемых типов в среду выполнения Windows
Передача массивов
Перегруженные методы
Асинхронные операции
Создание исключений
Объявление и вызов событий
Объявление типов в компонентах Среда выполнения Windows
Внутри компонента типы Среда выполнения Windows могут использовать любые функции .NET Framework, которые разрешены в приложении Магазина Windows. (Дополнительные сведения см. в разделе Обзор приложений .NET для Магазина Windows.) Снаружи члены ваших типов могут предоставлять доступ только к параметрам и возвращаемым значениями типов Среда выполнения Windows. В следующем списке описаны ограничения, действующие для типов .NET Framework, которые доступны в компонентах Среда выполнения Windows.
Поля, параметры и возвращаемые значения всех открытых типов и членов в ваших компонентах должны относиться к одному из следующих типов Среда выполнения Windows.
Это ограничение включает типы Среда выполнения Windows, которые вы создаете, а также типы, предоставляемые Среда выполнения Windows. Кроме того, оно включает некоторые типы .NET Framework. Поддержка этих типов .NET Framework позволяет более естественным образом использовать Среда выполнения Windows в управляемом коде: код использует привычные типы .NET Framework вместо соответствующих типов Среда выполнения Windows. Например, можно использовать простые типы .NET Framework, такие как Int32 и Double, некоторые фундаментальные типы, такие как DateTimeOffset и Uri, а также некоторые часто используемые универсальные типы интерфейсов, такие как IEnumerable<T> (IEnumerable(Of T) в Visual Basic) и IDictionary<TKey,TValue>. (Обратите внимание, что аргументами типа в этих универсальных типах должны быть типы Среда выполнения Windows.) Это описано в разделах Передача типов среды выполнения Windows в управляемый код и Передача управляемых типов в среду выполнения Windows.
Открытые классы и интерфейсы могут содержать методы, свойства и события. Можно объявить делегаты для событий либо использовать делегат EventHandler<T>. Открытые классы и интерфейсы не могут:
быть универсальными;
реализовывать интерфейсы, отличные от интерфейсов Среда выполнения Windows. (Однако вы можете создать собственные интерфейсы Среда выполнения Windows и реализовать их.)
наследовать классам, отсутствующим в Среда выполнения Windows, например классам System.Exception и System.EventArgs.
Корневое пространство имен всех открытых типов должно совпадать с именем сборки, а имя сборки не должно начинаться на "Windows".
Примечание
По умолчанию имена пространств имен в проектах Visual Studio совпадают с именами сборок. В Visual Basic оператор Namespace для данного пространства имен по умолчанию в коде не отображается.
Открытые структуры не могут иметь членов, отличных от открытых полей, а эти поля должны иметь тип значения или строковый тип.
Открытые классы должны объявляться с модификатором sealed (NotInheritable в Visual Basic). Если модель программирования требует полиморфизма, можно создать открытый интерфейс и реализовать его в классах, которые должны быть полиморфными.
Отладка компонента
Если приложение Магазина Windows и компонент построены с использованием управляемого кода, их можно отлаживать одновременно.
При тестировании компонента как части приложения Магазина Windows с использованием C++ можно одновременно отлаживать управляемый и машинный код. По умолчанию может отлаживаться только машинный код.
Одновременная отладка машинного кода C++ и управляемого кода
Откройте контекстное меню проекта Visual C++ и выберите пункт Свойства.
На страницах свойств в разделе Свойства конфигурации выберите Отладка.
Выберите Тип отладчика и в раскрывающемся списке замените значение Только машинный код на Смешанный (управляемый и машинный). Нажмите кнопку ОК.
Установите точки останова в машинном и управляемом коде.
При тестировании компонента как части приложения Магазина Windows с использованием JavaScript решение по умолчанию находится в режиме отладки JavaScript. В Visual Studio 2012 и Visual Studio Express 2012 для Windows 8 можно одновременно отлаживать код JavaScript и управляемый код.
Отладка управляемого кода вместо кода JavaScript
Откройте контекстное меню проекта JavaScript и выберите пункт Свойства.
На страницах свойств в разделе Свойства конфигурации выберите Отладка.
Выберите Тип отладчика и в раскрывающемся списке замените значение Только скрипт на Только управляемый код. Нажмите кнопку ОК.
Установите точки останова в машинном коде и выполните отладку обычным образом.
Передача типов Среда выполнения Windows в управляемый код
Как было сказано в разделе Объявление типов в компонентах среды выполнения Windows, некоторые типы .NET Framework могут встречаться в сигнатурах членов открытых классов. Это является частью возможностей .NET Framework, обеспечивающих естественное использование Среда выполнения Windows в управляемом коде. Эти возможности включают простые типы, а также некоторые классы и интерфейсы. Когда компонент используется из JavaScript или из кода C++, важно знать, как типы .NET Framework представляются в вызывающем объекте. Примеры с JavaScript см. в разделе Пошаговое руководство. Создание простого компонента в C# или Visual Basic и его вызов из кода JavaScript. В этом разделе рассматриваются часто используемые типы.
В .NET Framework у простых типов, таких как структура Int32, имеется множество полезных свойств и методов, например метод TryParse. В Среда выполнения Windows, напротив, простые типы имеют только поля. При передаче этих типов в управляемый код они представляются типами .NET Framework, и свойства и методы таких типов .NET Framework можно использовать обычным образом. В следующем списке перечислены подстановки, которые автоматически выполняются в интегрированной среде разработки:
вместо простых типов Среда выполнения Windows Int32, Int64, Single, Double, Boolean, String (неизменяемая коллекция символов Юникода), Enum, UInt32, UInt64 и Guid используются одноименные типы из пространства имен System;
вместо UInt8 используется тип System.Byte;
вместо Char16 используется тип System.Char;
вместо интерфейса IInspectable используется тип System.Object.
Если в языке C# или Visual Basic имеется ключевое слово для какого-либо из этих типов, можно использовать это ключевое слово языка.
Помимо простых типов в управляемом коде в форме эквивалентов из .NET Framework используются некоторые распространенные типы Среда выполнения Windows. Предположим, например, что в коде JavaScript используется класс Windows.Foundation.Uri, и соответствующий объект необходимо передать методу C# или Visual Basic. Эквивалентным типом в управляемом коде будет класс .NET Framework System.Uri, и именно он будет типом параметра метода. Можно легко понять, в каких случаях тип Среда выполнения Windows представляется типом .NET Framework, поскольку при написании управляемого кода система IntelliSense в Visual Studio скрывает тип Среда выполнения Windows и представляет эквивалентный тип .NET Framework. (Обычно имена таких двух типов совпадают. Но следует иметь в виду, что структура Windows.Foundation.DateTime отображается в управляемом коде как System.DateTimeOffset, а не как System.DateTime.)
Для некоторых часто используемых типов коллекций сопоставление устанавливается между интерфейсами, которые реализуются типом Среда выполнения Windows, и интерфейсами, которые реализуются соответствующим типом .NET Framework. Как и в случае вышеупомянутых типов, параметры объявляются с использованием типов .NET Framework. Это позволяет скрывать некоторые различия между типами и делает написание кода .NET Framework более естественным. В следующей таблице перечислены наиболее распространенные из этих типов универсальных интерфейсов, а также другие сопоставления распространенных классов и интерфейсов. Полный список типов Среда выполнения Windows, имеющих соответствие в .NET Framework, см. в разделе Сопоставление типов .NET Framework с типами среды выполнения Windows.
Среда выполнения Windows |
.NET Framework |
---|---|
IIterable<T> |
IEnumerable<T> |
IVector<T> |
IList<T> |
IVectorView<T> |
IReadOnlyList<T> |
IMap<K, V> |
IDictionary<TKey, TValue> |
IMapView<K, V> |
IReadOnlyDictionary<TKey, TValue> |
IKeyValuePair<K, V> |
KeyValuePair<TKey, TValue> |
IBindableIterable |
IEnumerable |
IBindableVector |
IList |
Windows.UI.Xaml.Data.INotifyPropertyChanged |
System.ComponentModel.INotifyPropertyChanged |
Windows.UI.Xaml.Data.PropertyChangedEventHandler |
System.ComponentModel.PropertyChangedEventHandler |
Windows.UI.Xaml.Data.PropertyChangedEventArgs |
System.ComponentModel.PropertyChangedEventArgs |
Если тип реализует несколько интерфейсов, в качестве типа параметра или типа возвращаемого значения члена можно использовать любой из этих интерфейсов. Например, можно передавать или возвращать тип Dictionary<int, string> (Dictionary(Of Integer, String) в Visual Basic) в качестве IDictionary<int, string>, IReadOnlyDictionary<int, string> или IEnumerable<System.Collections.Generic.KeyValuePair<TKey, TValue>>.
Важно!
В коде JavaScript используется интерфейс, занимающий первую позицию в списке интерфейсов, реализуемых управляемым типом. Например, если в код JavaScript возвращается тип Dictionary<int, string>, он отображается как IDictionary<int, string> независимо от того, какой интерфейс указан в качестве типа возвращаемого значения. Это означает, что если первый интерфейс не включает член, который отображается в последующих интерфейсах, этот член не будет видимым в JavaScript.
В Среда выполнения Windows перебор IMap<K, V> и IMapView<K, V> осуществляется с помощью IKeyValuePair. При передаче этих типов в управляемый код они представляются как IDictionary<TKey, TValue> и IReadOnlyDictionary<TKey, TValue>, поэтому для их перебора можно обычным образом использовать System.Collections.Generic.KeyValuePair<TKey, TValue>.
Представление интерфейсов в управляемом коде влияет на представление типов, реализующих эти интерфейсы. Например, класс PropertySet реализует интерфейс IMap<K, V>, который представляется в управляемом коде в виде IDictionary<TKey, TValue>. Тип PropertySet представляется, как если бы он реализовывал интерфейс IDictionary<TKey, TValue>, а не IMap<K, V>, поэтому в управляемом коде у него имеется метод Add, который работает, как метод Add словарей .NET Framework. А метода Insert у этого типа нет. Этот пример рассмотрен в статье Пошаговое руководство. Создание простого компонента в C# или Visual Basic и его вызов из кода JavaScript.
Передача управляемых типов в Среда выполнения Windows
Как было сказано в предыдущем разделе, некоторые типы Среда выполнения Windows могут представляться типами .NET Framework в сигнатурах методов компонентов или в сигнатурах членов Среда выполнения Windows при их использовании в интегрированной среде разработки. При передаче типов .NET Framework в эти члены или использовании их в качестве возвращаемых значений в членах компонентов на другой стороне они представляются как соответствующие типы Среда выполнения Windows. Примеры последствий вызова компонента из кода JavaScript см. в подразделе "Возвращение управляемых типов из компонента" раздела Пошаговое руководство. Создание простого компонента в C# или Visual Basic и его вызов из кода JavaScript.
Передача массивов
В Среда выполнения Windows все параметры являются входными или выходными; в ней нет параметров ref (ByRef в Visual Basic). Содержимое массивов, передаваемое в компонент Среда выполнения Windows, должно быть предназначено для ввода или для вывода. Иными словами, массивы должны обрабатываться как изменяемые. Если массив передается по значению (ByVal в Visual Basic), необходимо установить назначение с помощью атрибута ReadOnlyArrayAttribute или WriteOnlyArrayAttribute. См. раздел Передача массивов в компонент среды выполнения Windows.
Перегруженные методы
В Среда выполнения Windows методы можно перегружать. Однако при объявлении нескольких перегруженных методов с одинаковым количеством параметров атрибут Windows.Foundation.Metadata.DefaultOverloadAttribute должен применяться только к одной из этих перегрузок. Это будет единственная перегрузка, которую можно вызывать из JavaScript. Например, в следующем коде перегрузка, которая принимает значение int (Integer в Visual Basic) является перегрузкой по умолчанию.
public string OverloadExample(string s)
{
return s;
}
[Windows.Foundation.Metadata.DefaultOverload()]
public int OverloadExample(int x)
{
return x;
}
Public Function OverloadExample(ByVal s As String) As String
Return s
End Function
<Windows.Foundation.Metadata.DefaultOverload> _
Public Function OverloadExample(ByVal x As Integer) As Integer
Return x
End Function
Предупреждение
Javascript позволяет передавать в OverloadExample любое значение и приводит это значение к типу, требуемому для параметра. Можно вызвать OverloadExample со значением "forty-two", "42" или 42.3, но все они будут переданы перегруженному методу по умолчанию. В предыдущем примере перегруженный метод по умолчанию возвращает значения 0, 42 и 42 соответственно.
Атрибут DefaultOverloadAttribute нельзя применять к конструкторам. Все конструкторы в классе должны иметь различное число параметров.
Асинхронные операции
Чтобы реализовать в компоненте асинхронный метод, добавьте Async в конец имени метода и верните один из интерфейсов Среда выполнения Windows, представляющих асинхронные действия и операции: IAsyncAction, IAsyncActionWithProgress<TProgress>, IAsyncOperation<TResult> или IAsyncOperationWithProgress<TResult, TProgress>.
Для реализации асинхронных методов можно использовать задачи .NET Framework (класс Task и универсальный класс Task<TResult>). Необходимо вернуть задачу, которая представляет текущую операцию, например задачу, возвращаемую из асинхронного метода, написанного на C# или Visual Basic, или задачу, возвращаемую из метода Task.Run. При создании задачи с помощью конструктора необходимо перед возвращением задачи вызывать метод Task.Start.
Метод, который использует await (Await в Visual Basic), требует ключевого слова async (Async в Visual Basic). Если такой метод предоставляется компонентом Среда выполнения Windows, ключевое слово async следует применять к делегату, передаваемому в метод Run.
Для асинхронных действий и операций, которые не поддерживают отчеты об отмене или ходе выполнения, можно использовать метод WindowsRuntimeSystemExtensions.AsAsyncAction или метод расширения AsAsyncOperation<TResult>, чтобы заключать задачу в соответствующий интерфейс. Например, следующий код реализует асинхронный метод с помощью метода Task.Run, запускающего задачу. Метод расширения AsAsyncOperation<TResult> возвращает задачу как асинхронную операцию Среда выполнения Windows.
public static IAsyncOperation<IList<string>> DownloadAsStringsAsync(string id)
{
return Task.Run<IList<string>>(async () =>
{
var data = await DownloadDataAsync(id);
return ExtractStrings(data);
}).AsAsyncOperation();
}
Public Shared Function DownloadAsStringsAsync(ByVal id As String) _
As IAsyncOperation(Of IList(Of String))
Return Task.Run(Of IList(Of String))(
Async Function()
Dim data = Await DownloadDataAsync(id)
Return ExtractStrings(data)
End Function).AsAsyncOperation()
End Function
Следующий код JavaScript показывает, как вызывать метод с помощью объекта WinJS.Promise. Функция, которая передается методу then, выполняется при завершении асинхронного вызова. Параметр stringList содержит список строк, возвращаемый методом DownloadAsStringAsync, а функция выполняет все необходимые действия по обработке.
function asyncExample(id) {
var result = SampleComponent.Example.downloadAsStringAsync(id).then(
function (stringList) {
// Place code that uses the returned list of strings here.
});
}
Для асинхронных действий и операций, которые поддерживают отчеты об отмене и ходе выполнения, следует с помощью класса AsyncInfo создавать запущенную задачу и реализовывать функции отчетов об отмене и ходе выполнения с помощью аналогичных функций соответствующего интерфейса Среда выполнения Windows. Пример, в котором реализована поддержка отчетов об отмене и ходе выполнения, см. в разделе Пошаговое руководство. Создание простого компонента в C# или Visual Basic и его вызов из кода JavaScript.
Обратите внимание, что методы класса AsyncInfo можно использовать даже в том случае, если асинхронный метод не поддерживает отчеты об отмене и ходе выполнения. При использовании лямбда-функции Visual Basic или анонимного метода C# не указывайте параметры токена и интерфейса IProgress<T>. При использовании лямбда-функции C# указывайте параметр токена, но игнорируйте его. Предыдущий пример, в котором используется метод AsAsyncOperation<TResult>, будет выглядеть следующим образом, если вместо этого использовать перегрузку метода AsyncInfo.Run<TResult>(Func<CancellationToken, Task<TResult>>).
public static IAsyncOperation<IList<string>> DownloadAsStringsAsync(string id)
{
return AsyncInfo.Run<IList<string>>(async (token) =>
{
var data = await DownloadDataAsync(id);
return ExtractStrings(data);
});
}
Public Function OverloadExample(ByVal s As String) As String
Return s
End Function
<Windows.Foundation.Metadata.DefaultOverload> _
Public Function OverloadExample(ByVal x As Integer) As Integer
Return x
End Function
При создании асинхронного метода, который может поддерживать отчеты об отмене и ходе выполнения, попробуйте добавить перегруженные версии, которые не принимают параметры токена отмены или интерфейса IProgress<T>.
Создание исключений
Можно создавать исключения любого типа, входящего в Приложения .NET для Магазина Windows — поддерживаемые API. В компоненте Среда выполнения Windows нельзя объявлять собственные открытые типы исключений, но можно объявлять и создавать неоткрытые типы.
Если компонент не обрабатывает исключение, соответствующее исключение передается в код, который вызвал данный компонент. Представление этого исключения на вызывающей стороне зависит от того, каким образом язык вызова поддерживает Среда выполнения Windows.
В JavaScript исключение представляется объектом, в котором сообщение исключение заменено на трассировку стека. При отладке приложения в Visual Studio исходный текст сообщения можно видеть в диалоговом окне исключений отладчика с пометкой "Сведения WinRT". Исходный текст сообщения недоступен из кода JavaScript.
Примечание
В настоящее время трассировка стека содержит тип управляемого исключения, однако анализировать трассировку для определения типа исключения не рекомендуется. Вместо этого лучше использовать значение HRESULT, описанное далее в этом разделе.
В C++ исключение является исключением платформы. Если свойство HResult управляемого исключения может быть сопоставлено значению HRESULT конкретного исключения платформы, то используется конкретное исключение; в противном случае создается исключение Platform::COMException. Текст сообщения управляемого исключения недоступен в коде C++. Если было создано конкретное исключение платформы, отображается текст сообщения по умолчанию для этого типа исключений; в противном случае текст не отображается. См. раздел Исключения (C++/CX).
В C# и Visual Basic используется обычное управляемое исключение.
При создании в компоненте исключения можно упростить его обработку в вызывающем коде JavaScript или C++, если создавать исключения неоткрытых типов, свойство HResult которых связано с конкретным компонентом. Значение HRESULT доступно в вызывающем коде JavaScript через свойство number объекта исключения, а в коде C++ — через свойство COMException::HResult.
Примечание
Используйте для HRESULT отрицательное значение. Положительное значение интерпретируется как успех, и исключение в вызывающем коде JavaScript или C++ не создается.
Объявление и вызов событий
При объявлении типа для хранения данных для события создавайте класс, производный от Object, а не от EventArgs, поскольку EventArgs не является типом Среда выполнения Windows. Используйте EventHandler<TEventArgs> в качестве типа события и тип аргумента своего события в качестве аргумента универсального типа. Вызов событий осуществляется так же, как и в приложениях .NET Framework.
Когда компонент Среда выполнения Windows вызывается из JavaScript или C++, событие выполняется в соответствии с шаблоном событий Среда выполнения Windows, ожидаемым этими языками. Когда компонент вызывается из C# или Visual Basic, событие представляется обычным событием .NET Framework. Соответствующий пример можно найти в разделе Пошаговое руководство. Создание простого компонента в C# или Visual Basic и его вызов из кода JavaScript.
При реализации пользовательских методов доступа к событиям (событие объявляется с ключевым словом Custom в Visual Basic) в такой реализации необходимо соблюдать шаблон событий Среда выполнения Windows. См. раздел Пользовательские события и методы доступа к событиям в компонентах среды выполнения Windows. Обратите внимание, что при обработке события в коде C# или Visual Basic оно все равно представляется обычным событием .NET Framework.
См. также
Основные понятия
Обзор приложений .NET для Магазина Windows
Приложения .NET для Магазина Windows — поддерживаемые API
Создание компонентов среды выполнения Windows
Пользовательские события и методы доступа к событиям в компонентах среды выполнения Windows
Передача массивов в компонент среды выполнения Windows
Сопоставление типов .NET Framework с типами среды выполнения Windows
Диагностика состояний ошибки компонентов среды выполнения Windows