使用 C# 和 Visual Basic 创建 Windows 运行时组件Windows Runtime components with C# and Visual Basic

你可以使用托管代码创建自己的 Windows 运行时类型,并将其打包到 Windows 运行时组件中。You can use managed code to create your own Windows Runtime types and package them in a Windows Runtime component. 你可以在通用 Windows 平台 (UWP) 用 c + +、JavaScript、Visual Basic 或 c # 编写的应用程序中使用你的组件。You can use your component in Universal Windows Platform (UWP) apps that are written in C++, JavaScript, Visual Basic, or C#. 本主题概述了用于创建组件的规则,并讨论了有关 Windows 运行时的 .NET 支持的一些方面。This topic outlines the rules for creating a component, and discusses some aspects of .NET support for the Windows Runtime. 一般情况下,该支持设计为对 .NET 程序员透明可见。In general, that support is designed to be transparent to the .NET programmer. 但是,在你创建要与 JavaScript 或 C++ 一起使用的组件时,需要意识到这些语言支持 Windows 运行时的方法差异。However, when you create a component to use with JavaScript or C++, you need to be aware of differences in the way those languages support the Windows Runtime.

如果你正在创建仅用于以 Visual Basic 或 c # 编写的 UWP 应用的组件,并且该组件不包含 UWP 控件,则考虑使用 类库模板而 不是 Microsoft Visual Studio 中 Windows 运行时组件 项目模板。If you are creating a component for use only in UWP apps that are written in Visual Basic or C#, and the component does not contain UWP controls, then consider using the Class Library template instead of the Windows Runtime Component project template in Microsoft Visual Studio. 简单类库所受限制较少。There are fewer restrictions on a simple class library.

在 Windows 运行时组件中声明类型Declaring types in Windows Runtime components

在内部,组件中的 Windows 运行时类型可以使用 UWP 应用程序中允许的任何 .NET 功能。Internally, the Windows Runtime types in your component can use any .NET functionality that's allowed in a UWP app. 有关详细信息,请参阅适用 于 UWP 应用的 .netFor more info, see .NET for UWP apps.

在外部,类型的成员只能为其参数和返回值公开 Windows 运行时类型。Externally, the members of your types can expose only Windows Runtime types for their parameters and return values. 以下列表描述了从 Windows 运行时组件公开的 .NET 类型的限制。The following list describes the limitations on .NET types that are exposed from a Windows Runtime component.

  • 组件中的所有公共类型和成员的字段、参数和返回值必须是 Windows 运行时类型。The fields, parameters, and return values of all the public types and members in your component must be Windows Runtime types. 此限制包括你创作的 Windows 运行时类型以及 Windows 运行时本身提供的类型。This restriction includes the Windows Runtime types that you author as well as types that are provided by the Windows Runtime itself. 它还包括许多 .NET 类型。It also includes a number of .NET types. 包含这些类型是 .NET 提供的支持的一部分,它可以在托管代码中自然地使用 Windows 运行时 — 代码似乎使用熟悉的 .net 类型,而不是基础 Windows 运行时类型。The inclusion of these types is part of the support that .NET provides to enable the natural use of the Windows Runtime in managed code—your code appears to use familiar .NET types instead of the underlying Windows Runtime types. 例如,你可以使用诸如Int32Double的 .net 基元类型、某些基本类型(如DateTimeOffsetUri)以及一些常用的泛型接口类型,如ienumerable < t > ** (ienumerable () 的 Visual Basic) 和IDictionary < TKey,TValue > **。For example, you can use .NET primitive types such as Int32 and Double, certain fundamental types such as DateTimeOffset and Uri, and some commonly used generic interface types such as IEnumerable<T> (IEnumerable(Of T) in Visual Basic) and IDictionary<TKey,TValue>. 请注意,这些泛型类型的类型参数必须是 Windows 运行时类型。Note that the type arguments of these generic types must be Windows Runtime types. 本主题后面的将 Windows 运行时类型传递给托管代码将托管类型传递给 Windows 运行时部分对此进行了讨论。This is discussed in the sections Passing Windows Runtime types to managed code and Passing managed types to the Windows Runtime, later in this topic.

  • 公共类和接口可以包含方法、属性和事件。Public classes and interfaces can contain methods, properties, and events. 可以为事件声明委托,或使用**EventHandler < T > **委托。You can declare delegates for your events, or use the EventHandler<T> delegate. 公共类或接口不能:A public class or interface can't:

    • 具有泛型性。Be generic.
    • 实现一个接口,该接口不是 Windows 运行时接口 (不过,你可以创建自己的 Windows 运行时接口并) 实现它们。Implement an interface that is not a Windows Runtime interface (however, you can create your own Windows Runtime interfaces and implement them).
    • 从不在 Windows 运行时中的类型派生 ,如 system.exception 和 system.objectDerive from types that are not in the Windows Runtime, such as System.Exception and System.EventArgs.
  • 所有公共类型必须具有匹配程序集名的根命名空间,并且程序集名不得以“Windows”开头。All public types must have a root namespace that matches the assembly name, and the assembly name must not begin with "Windows".

    提示Tip. 默认情况下,Visual Studio 项目具有与程序集名称匹配的命名空间名称。By default, Visual Studio projects have namespace names that match the assembly name. 在 Visual Basic 中,此默认命名空间的命名空间声明不会显示在代码中。In Visual Basic, the Namespace statement for this default namespace is not shown in your code.

  • 公共结构无法具有公共字段以外的任何成员,并且这些字段必须是值类型或字符串。Public structures can't have any members other than public fields, and those fields must be value types or strings.

  • 公共类必须是 sealed(在 Visual Basic 中是 NotInheritable)。Public classes must be sealed (NotInheritable in Visual Basic). 如果编程模型要求多态性,则可以创建一个公共接口,并在必须为多态的类中实现该接口。If your programming model requires polymorphism, then you can create a public interface, and implement that interface on the classes that must be polymorphic.

调试组件Debugging your component

如果 UWP 应用和组件都是用托管代码生成的,则可以同时调试它们。If both your UWP app and your component are built with managed code, then you can debug them both at the same time.

使用 c + + 在 UWP 应用中测试组件时,可以同时调试托管代码和本机代码。When you're testing your component as part of a UWP app using C++, you can debug managed and native code at the same time. 默认情况下仅调试本机代码。The default is native code only.

调试本机 C++ 代码和托管代码To debug both native C++ code and managed code

  1. 打开 Visual C++ 项目的快捷菜单,并选择“属性”****。Open the shortcut menu for your Visual C++ project, and choose Properties.
  2. 在属性页面的“配置属性”**** 下,选择“调试”****。In the property pages, under Configuration Properties, choose Debugging.
  3. 选择“调试器类型”****,并在下拉列表框中将“仅限本机”**** 更改为“混合(托管和本机)”****。Choose Debugger Type, and in the drop-down list box change Native Only to Mixed (Managed and Native). 选择“确定”。Choose OK.
  4. 在本机代码和托管代码中设置断点。Set breakpoints in native and managed code.

使用 JavaScript 将组件作为 UWP 应用的一部分进行测试时,默认情况下该解决方案处于 JavaScript 调试模式。When you're testing your component as part of a UWP app using JavaScript, by default the solution is in JavaScript debugging mode. 在 Visual Studio 中,无法同时调试 JavaScript 和托管代码。In Visual Studio, you can't debug JavaScript and managed code at the same time.

调试托管代码而非 JavaScriptTo debug managed code instead of JavaScript

  1. 打开 JavaScript 项目的快捷菜单,并选择“属性”****。Open the shortcut menu for your JavaScript project, and choose Properties.
  2. 在属性页面的“配置属性”**** 下,选择“调试”****。In the property pages, under Configuration Properties, choose Debugging.
  3. 选择“调试器类型”****,并在下拉列表框中将“仅限脚本”**** 更改为“仅限托管”****。Choose Debugger Type, and in the drop-down list box change Script Only to Managed Only. 选择“确定”。Choose OK.
  4. 在托管代码中设置断点,并像往常一样调试。Set breakpoints in managed code and debug as usual.

将 Windows 运行时类型传递到托管代码Passing Windows Runtime types to managed code

如前面在 Windows 运行时组件中声明类型部分中所述,某些 .net 类型可能出现在公共类的成员签名中。As mentioned previously in the section Declaring types in Windows Runtime components, certain .NET types can appear in the signatures of members of public classes. 这是 .NET 提供的支持的一部分,用于在托管代码中自然地使用 Windows 运行时。This is part of the support that .NET provides to enable the natural use of the Windows Runtime in managed code. 它包含基元类型以及某些类和接口。It includes primitive types and some classes and interfaces. 当你的组件从 JavaScript 或 c + + 代码中使用时,请务必了解 .NET 类型如何显示给调用方。When your component is used from JavaScript, or from C++ code, it's important to know how your .NET types appear to the caller. 有关使用 JavaScript 的示例,请参阅 创建 c # 或 Visual Basic Windows 运行时组件的演练,并从 javascript 调用它See Walkthrough of creating a C# or Visual Basic Windows Runtime component, and calling it from JavaScript for examples with JavaScript. 本部分讨论常用类型。This section discusses commonly used types.

在 .NET 中,基元类型(如 Int32 结构)具有许多有用的属性和方法,例如 TryParse 方法。In .NET, primitive types such as the Int32 structure have many useful properties and methods, such as the TryParse method. 相比之下,Windows 运行时中的基元类型和结构则仅拥有字段。By contrast, primitive types and structures in the Windows Runtime only have fields. 将这些类型传递给托管代码时,它们看起来像 .NET 类型,您可以像往常一样使用 .NET 类型的属性和方法。When you pass these types to managed code, they appear to be .NET types, and you can use the properties and methods of .NET types as you normally would. 下表总结了在 IDE 中自动进行的替换:The following list summarizes the substitutions that are made automatically in the IDE:

  • 对于 Windows 运行时基元 Int32Int64SingleDoubleBooleanString (不可变的 Unicode 字符集合) 、 EnumUInt32UInt64Guid,请使用 System 命名空间中具有相同名称的类型。For the Windows Runtime primitives Int32, Int64, Single, Double, Boolean, String (an immutable collection of Unicode characters), Enum, UInt32, UInt64, and Guid, use the type of the same name in the System namespace.
  • 对于 UInt8,请使用 system.objectFor UInt8, use System.Byte.
  • 对于 Char16,请使用 system.objectFor Char16, use System.Char.
  • 对于 IInspectable 接口,请使用 system.objectFor the IInspectable interface, use System.Object.

如果 c # 或 Visual Basic 为上述任意类型提供语言关键字,则可改用 language 关键字。If C# or Visual Basic provides a language keyword for any of these types, then you can use the language keyword instead.

除基元类型外,某些基本的常用 Windows 运行时类型在托管代码中显示为其 .NET 等效项。In addition to primitive types, some basic, commonly used Windows Runtime types appear in managed code as their .NET equivalents. 例如,假设你的 JavaScript 代码使用了 Windows. 地基 类,并且你想要将其传递给 c # 或 Visual Basic 方法。For example, suppose your JavaScript code uses the Windows.Foundation.Uri class, and you want to pass it to a C# or Visual Basic method. 托管代码中的等效类型是 .NET system.object 类,并且这是用于方法参数的类型。The equivalent type in managed code is the .NET System.Uri class, and that's the type to use for the method parameter. 你可以知道 Windows 运行时类型显示为 .NET 类型的时间,因为 Visual Studio 中的 IntelliSense 会在你编写托管代码时隐藏 Windows 运行时类型,并显示等效的 .NET 类型。You can tell when a Windows Runtime type appears as a .NET type, because IntelliSense in Visual Studio hides the Windows Runtime type when you're writing managed code, and presents the equivalent .NET type. (通常,这两种类型具有相同名称。(Usually the two types have the same name. 但请注意, Windows node.js 结构在托管代码中显示为 system.exception,而不是作为 system.object。 ) However, note that the Windows.Foundation.DateTime structure appears in managed code as System.DateTimeOffset and not as System.DateTime.)

对于某些常用的集合类型,映射位于 Windows 运行时类型所实现的接口与相应 .NET 类型实现的接口之间。For some commonly used collection types, the mapping is between the interfaces that are implemented by a Windows Runtime type and the interfaces that are implemented by the corresponding .NET type. 与上面提到的类型一样,可以使用 .NET 类型声明参数类型。As with the types mentioned above, you declare parameter types by using the .NET type. 这隐藏了类型之间的一些差异,并使编写 .NET 代码更自然。This hides some differences between the types and makes writing .NET code more natural.

下表列出了最常见的泛型接口类型以及其他常见的类和接口映射。The following table lists the most common of these generic interface types, along with other common class and interface mappings. 有关 .NET 映射的 Windows 运行时类型的完整列表,请参阅 Windows 运行时类型的 .net 映射For a complete list of Windows Runtime types that .NET maps, see .NET mappings of Windows Runtime types.

Windows 运行时Windows Runtime .NET.NET
IIterable<T>IIterable<T> IEnumerable < T>IEnumerable<T>
IVector<T>IVector<T> IList < T>IList<T>
IVectorView<T>IVectorView<T> IReadOnlyList < T>IReadOnlyList<T>
IMap < K,V>IMap<K, V> IDictionary < TKey,TValue>IDictionary<TKey, TValue>
IMapView<K, V>IMapView<K, V> System.collections.generic.ireadonlydictionary<tkey < TKey,TValue>IReadOnlyDictionary<TKey, TValue>
IKeyValuePair < K,V>IKeyValuePair<K, V> KeyValuePair < TKey,TValue>KeyValuePair<TKey, TValue>
IBindableIterableIBindableIterable IEnumerableIEnumerable
IBindableVectorIBindableVector IListIList
Windows.UI.Xaml.Data.INotifyPropertyChangedWindows.UI.Xaml.Data.INotifyPropertyChanged System.ComponentModel.INotifyPropertyChangedSystem.ComponentModel.INotifyPropertyChanged
Windows.UI.Xaml.Data.PropertyChangedEventHandlerWindows.UI.Xaml.Data.PropertyChangedEventHandler System.ComponentModel.PropertyChangedEventHandlerSystem.ComponentModel.PropertyChangedEventHandler
Windows.UI.Xaml.Data.PropertyChangedEventArgsWindows.UI.Xaml.Data.PropertyChangedEventArgs System.ComponentModel.PropertyChangedEventArgsSystem.ComponentModel.PropertyChangedEventArgs

在某种类型实现多个接口时,你可以将所实现的任意接口用作成员的参数类型或返回类型。When a type implements more than one interface, you can use any of the interfaces it implements as a parameter type or return type of a member. 例如,你可以将字典 < int > 、string (字典 (作为IDictionary < int、 > string、 **system.collections.generic.ireadonlydictionary<tkey < int、string > IEnumerable < KeyValuePair < TKey,TValue > > 传递或返回整数、string) **在) Visual Basic 中。For example, you can pass or return a Dictionary<int, string> (Dictionary(Of Integer, String) in Visual Basic) as IDictionary<int, string>, IReadOnlyDictionary<int, string>, or IEnumerable<System.Collections.Generic.KeyValuePair<TKey, TValue>>.

重要

JavaScript 使用托管类型实现的、在接口列表中显示在最前面的接口。JavaScript uses the interface that appears first in the list of interfaces that a managed type implements. 例如,如果您将字典 < int 和 > String返回到 JavaScript 代码,无论您指定哪一个接口作为返回类型,它都显示为**IDictionary < int,string > ** 。For example, if you return Dictionary<int, string> to JavaScript code, it appears as IDictionary<int, string> no matter which interface you specify as the return type. 这意味着,如果第一个接口不包括显示在后续接口上的成员,JavaScript 将看不到该成员。This means that if the first interface doesn't include a member that appears on later interfaces, that member isn't visible to JavaScript.

在 Windows 运行时中,使用 IKeyValuePair 循环访问IMap < k、 > v和**IMapView < K,v > ** 。In the Windows Runtime, IMap<K, V> and IMapView<K, V> are iterated by using IKeyValuePair. 当你将它们传递给托管代码时,它们将显示为**IDictionary < TKey、TValue > system.collections.generic.ireadonlydictionary<tkey < TKey,TValue > ,因此,你可以自然地使用 < KeyValuePair,TKey > **来枚举它们。When you pass them to managed code, they appear as IDictionary<TKey, TValue> and IReadOnlyDictionary<TKey, TValue>, so naturally you use System.Collections.Generic.KeyValuePair<TKey, TValue> to enumerate them.

接口在托管代码中的显示方式将影响实现这些接口的类型的显示方式。The way interfaces appear in managed code affects the way types that implement these interfaces appear. 例如, PropertySet类实现IMap < K, > V,后者在托管代码中显示为**IDictionary < TKey,TValue > **。For example, the PropertySet class implements IMap<K, V>, which appears in managed code as IDictionary<TKey, TValue>. PropertySet看起来像是实现了 < IDictionary TKey、 > TValue而不是IMap < K > ,V,因此在托管代码中,它看起来像是 .net字典上的add方法。PropertySet appears as if it implemented IDictionary<TKey, TValue> instead of IMap<K, V>, so in managed code it appears to have an Add method, which behaves like the Add method on .NET dictionaries. 它看起来没有 Insert 方法。It doesn't appear to have an Insert method. 您可以在 创建 c # 或 Visual Basic Windows 运行时组件的主题演练中查看此示例,并从 JavaScript 中调用它You can see this example in the topic Walkthrough of creating a C# or Visual Basic Windows Runtime component, and calling it from JavaScript.

将托管的类型传递到 Windows 运行时Passing managed types to the Windows Runtime

如前一部分中所述,某些 Windows 运行时类型可以在组件成员的签名中显示为 .NET 类型,也可以在 IDE 中使用时在 Windows 运行时成员的签名中显示。As discussed in the previous section, some Windows Runtime types can appear as .NET types in the signatures of your component's members, or in the signatures of Windows Runtime members when you use them in the IDE. 将 .NET 类型传递给这些成员或将其用作组件成员的返回值时,它们将在另一端作为相应的 Windows 运行时类型出现在另一端。When you pass .NET types to these members or use them as the return values of your component's members, they appear to the code on the other side as the corresponding Windows Runtime type. 有关从 JavaScript 调用组件时这可能产生的影响的示例,请参阅 创建 c # 或 Visual Basic Windows 运行时组件的演练中的 "从组件中返回托管类型" 部分,然后从 javascript 中调用它。For examples of the effects this can have when your component is called from JavaScript, see the "Returning managed types from your component" section in Walkthrough of creating a C# or Visual Basic Windows Runtime component, and calling it from JavaScript.

重载的方法Overloaded methods

在 Windows 运行时中,可重载方法。In the Windows Runtime, methods can be overloaded. 但是,如果使用相同数量的参数声明多个重载,则必须仅将 windows.foundation.metadata.defaultoverloadattribute 属性应用于这些重载之一。However, if you declare multiple overloads with the same number of parameters, you must apply the Windows.Foundation.Metadata.DefaultOverloadAttribute attribute to only one of those overloads. 该重载是唯一能够通过 JavaScript 调用的重载。That overload is the only one you can call from JavaScript. 例如,在以下代码中,接受 int(在 Visual Basic 中是 Integer)的重载是默认重载。For example, in the following code the overload that takes an int (Integer in Visual Basic) is the default overload.

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传递任何值,并将值强制转换为参数所需的类型。[IMPORTANT] JavaScript allows you to pass any value to OverloadExample, and coerces the value to the type that is required by the parameter. 可以通过 "42"、"42" 或42.3 调用 OverloadExample ,但是所有这些值都将传递给默认重载。You can call OverloadExample with "forty-two", "42", or 42.3, but all those values are passed to the default overload. 上一示例中的默认重载分别返回0、42和42。The default overload in the previous example returns 0, 42, and 42, respectively.

不能将 DefaultOverloadAttribute 特性应用到构造函数。You can't apply the DefaultOverloadAttribute attribute to constructors. 类中的所有构造函数必须具有不同数量的参数。All the constructors in a class must have different numbers of parameters.

实现 IStringableImplementing IStringable

从 Windows 8.1 开始,Windows 运行时包括 IStringable 接口,该接口的单一方法 IStringable提供的基本格式设置支持可与 Object. tostring提供的格式支持。Starting with Windows 8.1, the Windows Runtime includes an IStringable interface whose single method, IStringable.ToString, provides basic formatting support comparable to that provided by Object.ToString. 如果选择在 Windows 运行时组件中导出的公共托管类型中实现 IStringable ,则以下限制适用:If you do choose to implement IStringable in a public managed type that is exported in a Windows Runtime component, the following restrictions apply:

  • 只能在 "类实现" 关系中定义 IStringable 接口,如 c # 中的以下代码:You can define the IStringable interface only in a "class implements" relationship, such as the following code in C#:

    public class NewClass : IStringable
    

    或以下 Visual Basic 代码:Or the following Visual Basic code:

    Public Class NewClass : Implements IStringable
    
  • 无法在接口上实现 IStringableYou can't implement IStringable on an interface.

  • 不能将参数声明为 IStringable类型。You can't declare a parameter to be of type IStringable.

  • IStringable 不能是方法、属性或字段的返回类型。IStringable can't be the return type of a method, property, or field.

  • 你无法通过使用如下所示的方法定义,从基类中隐藏 IStringable 实现:You can't hide your IStringable implementation from base classes by using a method definition such as the following:

    public class NewClass : IStringable
    {
       public new string ToString()
       {
          return "New ToString in NewClass";
       }
    }
    

    相反, IStringable 实现必须始终重写基类实现。Instead, the IStringable.ToString implementation must always override the base class implementation. 只能通过对强类型类实例调用 ToString 实现来隐藏该实现。You can hide a ToString implementation only by invoking it on a strongly typed class instance.

备注

在各种条件下,从本机代码到实现 IStringable 或隐藏其 ToString 实现的托管类型的调用可能会产生意外行为。Under a variety of conditions, calls from native code to a managed type that implements IStringable or hides its ToString implementation can produce unexpected behavior.

异步操作Asynchronous operations

若要在组件中实现异步方法,请将 "Async" 添加到方法名称的末尾,并返回一个表示异步操作或操作的 Windows 运行时接口: IAsyncAction、 **iasyncactionwithprogress < TProgress > **、 **iasyncoperation < TResult > IAsyncOperationWithProgress < TResult,TProgress > **。To implement an asynchronous method in your component, add "Async" to the end of the method name and return one of the Windows Runtime interfaces that represent asynchronous actions or operations: IAsyncAction, IAsyncActionWithProgress<TProgress>, IAsyncOperation<TResult>, or IAsyncOperationWithProgress<TResult, TProgress>.

您可以使用 (任务类和泛型**任务 < TResult > **类) 的 .net 任务来实现异步方法。You can use .NET tasks (the Task class and generic Task<TResult> class) to implement your asynchronous method. 必须返回表示正在进行的操作的任务,例如从使用 c # 或 Visual Basic 编写的异步方法中返回的任务,或者从该任务返回的任务 。运行 方法。You must return a task that represents an ongoing operation, such as a task that is returned from an asynchronous method written in C# or Visual Basic, or a task that is returned from the Task.Run method. 如果你使用构造函数创建任务,必须在返回它之前调用其 Task.Start 方法。If you use a constructor to create the task, you must call its Task.Start method before returning it.

使用 await Visual Basic) 中的 (的方法 Await 要求 (Visual Basic) async 中的关键字 AsyncA method that uses await (Await in Visual Basic) requires the async keyword (Async in Visual Basic). 如果从 Windows 运行时组件公开此类方法,请将关键字应用于 async 传递给 Run 方法的委托。If you expose such a method from a Windows Runtime component, apply the async keyword to the delegate that you pass to the Run method.

对于不支持取消和进度报告的异步操作,你可以使用 WindowsRuntimeSystemExtensions.AsAsyncActionAsAsyncOperation<TResult> 扩展方法来在相应的接口中打包任务。For asynchronous actions and operations that do not support cancellation or progress reporting, you can use the WindowsRuntimeSystemExtensions.AsAsyncAction or AsAsyncOperation<TResult> extension method to wrap the task in the appropriate interface. 例如,下面的代码使用任务来实现异步方法 **。运行 < TResult > **方法来启动任务。For example, the following code implements an asynchronous method by using the Task.Run<TResult> method to start a task. **AsAsyncOperation < TResult > **扩展方法将任务作为 Windows 运行时异步操作返回。The AsAsyncOperation<TResult> extension method returns the task as a Windows Runtime asynchronous operation.

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 对象调用方法。The following JavaScript code shows how the method could be called by using a WinJS.Promise object. 然后,传递到该方法的函数在完成异步调用时执行。The function that is passed to the then method is executed when the asynchronous call completes. StringList 参数包含 DownloadAsStringAsync 方法返回的字符串的列表,该函数执行所需的任何处理。The stringList parameter contains the list of strings that is returned by the DownloadAsStringAsync method, and the function does whatever processing is required.

function asyncExample(id) {

    var result = SampleComponent.Example.downloadAsStringAsync(id).then(
        function (stringList) {
            // Place code that uses the returned list of strings here.
        });
}

对于支持取消或进度报告的异步操作和操作,请使用 system.runtime.interopservices.windowsruntime.asyncinfo 类生成已启动的任务,并将该任务的取消和进度报告功能与相应 Windows 运行时接口的取消和进度报告功能挂钩。For asynchronous actions and operations that support cancellation or progress reporting, use the AsyncInfo class to generate a started task and to hook up the cancellation and progress reporting features of the task with the cancellation and progress reporting features of the appropriate Windows Runtime interface. 有关支持取消和进度报告的示例,请参阅 创建 c # 或 Visual Basic Windows 运行时组件的演练,并从 JavaScript 调用它For an example that supports both cancellation and progress reporting, see Walkthrough of creating a C# or Visual Basic Windows Runtime component, and calling it from JavaScript.

请注意,即使异步方法不支持取消或进度报告,也可以使用 system.runtime.interopservices.windowsruntime.asyncinfo 类的方法。Note that you can use the methods of the AsyncInfo class even if your asynchronous method doesn't support cancellation or progress reporting. 如果使用 Visual Basic lambda 函数或 c # 匿名方法,请不要为标记和**iprogress < t > **接口提供参数。If you use a Visual Basic lambda function or a C# anonymous method, don't supply parameters for the token and IProgress<T> interface. 如果你使用 C# lambda 函数,则提供令牌参数,但忽略它。If you use a C# lambda function, supply a token parameter but ignore it. 上面的示例使用 AsAsyncOperation < TResult > 方法,当你使用 system.runtime.interopservices.windowsruntime.asyncinfo 时,它将如下所示。**运行 < tresult > (Func < CancellationToken,任务 < TResult > > **) 方法重载。The previous example, which used the AsAsyncOperation<TResult> method, looks like this when you use the AsyncInfo.Run<TResult>(Func<CancellationToken, Task<TResult>>) method overload instead.

public static IAsyncOperation<IList<string>> DownloadAsStringsAsync(string id)
{
    return AsyncInfo.Run<IList<string>>(async (token) =>
    {
        var data = await DownloadDataAsync(id);
        return ExtractStrings(data);
    });
}
Public Shared Function DownloadAsStringsAsync(ByVal id As String) _
    As IAsyncOperation(Of IList(Of String))

    Return AsyncInfo.Run(Of IList(Of String))(
        Async Function()
            Dim data = Await DownloadDataAsync(id)
            Return ExtractStrings(data)
        End Function)
End Function

如果创建可以选择支持取消或进度报告的异步方法,请考虑添加没有参数的重载或**iprogress < t > **接口。If you create an asynchronous method that optionally supports cancellation or progress reporting, consider adding overloads that don't have parameters for a cancellation token or the IProgress<T> interface.

引发异常Throwing exceptions

你可以引发任何包括在适用于 Windows 应用的 .NET 中的异常类型。You can throw any exception type that is included in the .NET for Windows apps. 你无法在 Windows 运行时组件中声明自己的公共异常类型,但可以声明并引发非公共类型。You can't declare your own public exception types in a Windows Runtime component, but you can declare and throw non-public types.

如果组件不处理异常,将在调用组件的代码中引发相应异常。If your component doesn't handle the exception, a corresponding exception is raised in the code that called your component. 向调用方显示异常的方式取决于调用语言支持 Windows 运行时的方式。The way the exception appears to the caller depends on the way the calling language supports the Windows Runtime.

  • 在 JavaScript 中,异常显示为堆栈跟踪替换异常消息的对象。In JavaScript, the exception appears as an object in which the exception message is replaced by a stack trace. 在 Visual Studio 中调试应用时,你可以看到显示在调试器异常对话框中标识为“WinRT 信息”的原始消息文本。When you debug your app in Visual Studio, you can see the original message text displayed in the debugger exception dialog box, identified as "WinRT Information". 无法从 JavaScript 代码访问原始消息文本。You can't access the original message text from JavaScript code.

    提示Tip.目前,堆栈跟踪包含托管异常类型,但我们不建议你分析跟踪来标识异常类型。 Currently, the stack trace contains the managed exception type, but we don't recommend parsing the trace to identify the exception type. 改为使用 HRESULT 值,如本部分后面所述。Instead, use an HRESULT value as described later in this section.

  • 在 C++ 中,异常显示为平台异常。In C++, the exception appears as a platform exception. 如果托管异常的 HResult 属性可映射到特定平台异常的 HRESULT,则使用特定异常;否则,将引发 Platform:: COMException 异常。If the managed exception's HResult property can be mapped to the HRESULT of a specific platform exception, the specific exception is used; otherwise, a Platform::COMException exception is thrown. 托管异常的消息文本不适用于 C++ 代码。The message text of the managed exception is not available to C++ code. 如果已引发特定平台异常,将显示该异常类型的默认消息文本;否则,将不显示任何消息文本。If a specific platform exception was thrown, the default message text for that exception type appears; otherwise, no message text appears. 请参阅异常 (C++/CX)See Exceptions (C++/CX).

  • 在 C# 或 Visual Basic 中,异常是正常的托管异常。In C# or Visual Basic, the exception is a normal managed exception.

在从组件引发异常时,你可以使 JavaScript 或 C++ 调用方处理异常变得更简单,方法是引发其 HResult 属性值特定于你的组件的非公共异常类型。When you throw an exception from your component, you can make it easier for a JavaScript or C++ caller to handle the exception by throwing a non-public exception type whose HResult property value is specific to your component. 通过 COMException:: hresult 属性,通过异常对象的 number 属性和 c + + 调用方可以使用 HRESULT。The HRESULT is available to a JavaScript caller through the exception object's number property, and to a C++ caller through the COMException::HResult property.

备注

为 HRESULT 使用负值。Use a negative value for your HRESULT. 正值解释为成功,并且在 JavaScript 或 C++ 调用方中没有引发任何异常。A positive value is interpreted as success, and no exception is thrown in the JavaScript or C++ caller.

声明和引发事件Declaring and raising events

在你声明类型以保留事件数据时,请从 Object 而非 EventArgs 派生,因为 EventArgs 不属于 Windows 运行时类型。When you declare a type to hold the data for your event, derive from Object instead of from EventArgs, because EventArgs is not a Windows Runtime type. 使用**EventHandler < TEventArgs > **作为事件的类型,并使用事件参数类型作为泛型类型参数。Use EventHandler<TEventArgs> as the type of the event, and use your event argument type as the generic type argument. 与在 .NET 应用程序中一样,引发事件。Raise the event just as you would in a .NET application.

在通过 JavaScript 或 C++ 使用 Windows 运行时组件时,事件遵循这些语言期望的 Windows 运行时事件模式。When your Windows Runtime component is used from JavaScript or C++, the event follows the Windows Runtime event pattern that those languages expect. 使用 c # 或 Visual Basic 中的组件时,事件显示为普通的 .NET 事件。When you use the component from C# or Visual Basic, the event appears as an ordinary .NET event. 创建 c # 或 Visual Basic Windows 运行时组件的演练中提供了一个示例,并从 JavaScript 调用它An example is provided in Walkthrough of creating a C# or Visual Basic Windows Runtime component, and calling it from JavaScript.

如果要实现自定义事件访问器(在 Visual Basic 中通过 Custom 关键字声明事件),必须在实现中遵循 Windows 运行时事件模式。If you implement custom event accessors (declare an event with the Custom keyword, in Visual Basic), you must follow the Windows Runtime event pattern in your implementation. 请参阅 Windows 运行时组件中的自定义事件和事件访问器See Custom events and event accessors in Windows Runtime components. 请注意,在处理 c # 或 Visual Basic 代码中的事件时,该事件仍显示为普通的 .NET 事件。Note that when you handle the event from C# or Visual Basic code, it still appears to be an ordinary .NET event.

后续步骤Next steps

在创建了 Windows 运行时组件以供自己使用后,你可能会发现它封装的功能对其他开发人员也很有用。After you’ve created a Windows Runtime component for your own use, you may find that the functionality it encapsulates is useful to other developers. 若要打包组件以分配给其他开发人员,你有两个选择。You have two options for packaging a component for distribution to other developers. 请参阅分配托管的 Windows 运行时组件See Distributing a managed Windows Runtime component.

有关 Visual Basic 和 c # 语言功能以及对 Windows 运行时的 .NET 支持的详细信息,请参阅 Visual Basic 和 c # 语言参考For more information about Visual Basic and C# language features, and .NET support for the Windows Runtime, see Visual Basic and C# language reference.

疑难解答Troubleshooting

症状Symptom 纠正方法Remedy
在 c + +/WinRT 应用中,当使用使用 XAML 的 c # Windows 运行时组件 时,编译器将生成 "MyNamespace_XamlTypeInfo" 形式的错误 :不是 "WinRT:: MyNamespace" 的成员, — 其中 MyNamespace 是 Windows 运行时组件命名空间的名称。In a C++/WinRT app, when consuming a C# Windows Runtime component that uses XAML, the compiler produces an error of the form "'MyNamespace_XamlTypeInfo': is not a member of 'winrt::MyNamespace'"—where MyNamespace is the name of the Windows Runtime component's namespace. pch.h 使用 c + +/WinRT 应用程序中,添加 #include <winrt/MyNamespace.MyNamespace_XamlTypeInfo.h> — 相应的替换MyNamespaceIn pch.h in the consuming C++/WinRT app, add #include <winrt/MyNamespace.MyNamespace_XamlTypeInfo.h>—replacing MyNamespace as appropriate.