诊断 C#/WinRT 组件错误

本文提供有关对使用 C#/WinRT 编写的 Windows 运行时组件的限制的其他信息。 它扩展了作者在生成组件时 C#/WinRT 的错误消息中提供的信息。 对于现有的 UWP .NET Native 托管组件,C# WinRT 组件的元数据是使用 Winmdexp.exe(一种 .NET 工具)生成的。 现在,Windows 运行时支持已从 .NET 中分离出来,C#/WinRT 提供了从组件中生成 .winmd 文件的工具。 Windows 运行时对代码的约束比 C# 类库更多,且 C#/WinRT 诊断扫描程序在生成 .winmd 文件之前会提醒你注意这些约束。

本文介绍了在 C#/WinRT 中生成时报告的错误。 本文是有关使用 Winmdexp.exe 工具的现有 UWP .NET Native 托管组件的限制信息的更新版本。

搜索错误消息文本(省略占位符的特定值)或消息编号。 如果你在此处没有找到所需信息,可使用本文末尾的“反馈”按钮帮助我们改进这篇文档。 请在反馈中提供错误消息。 或者,你可以在 C#/WinRT 存储库处提交 Bug。

本文按场景组织错误消息。

实现不是有效的 Windows 运行时接口的接口

C#/WinRT 组件无法实现某些 Windows 运行时接口,例如表示异步操作的 Windows 运行时接口(IAsyncAction、IAsyncActionWithProgressTProgress、IAsyncOperationTResult> 或 >。 转而使用 AsyncInfo 类在 Windows 运行时组件中生成异步操作。 注意:这些不是唯一无效的接口;例如,一个类不能实现 System.Exception。

错误号

消息正文

CsWinRT1008

Windows 运行时组件类型 {0} 无法实现接口 {1},因为该接口不是有效的 Windows 运行时接口

在 Windows 运行时中,重载的方法仅在一个重载指定为默认重载时才能具有相同数量的参数。 使用特性 Windows.Foundation.Metadata.DefaultOverload(CsWinRT1015、1016)。

当数组用作函数或属性中的输入或输出时,它们必须为只读或只写 (CsWinRT 1025)。 提供了特性 System.Runtime.InteropServices.WindowsRuntime.ReadOnlyArray 和 System.Runtime.InteropServices.WindowsRuntime.WriteOnlyArray 供你使用。 提供的特性仅用于数组类型 (CsWinRT1026) 的参数,每个参数只能应用一个特性 (CsWinRT1023)。

不需要对标记为“输出”的数组参数应用任何特性,因为它被假定为只写参数。 在本例中,如果将它修饰为只读,随即会出现一条错误消息 (CsWinRT1024)。

特性 System.Runtime.InteropServices.InAttribute 和 System.Runtime.InteropServices.OutAttribute 不应该用于任何类型的参数 (CsWinRT 1021、1022)。

错误号

消息正文

CsWinRT1015

在类 {2} 中:“{1}”的多个 {0} 参数重载使用 Windows.Foundation.Metadata.DefaultOverloadAttribute 进行修饰。 该特性只能应用于该方法的一个重载。

CsWinRT1016

在类 {2} 中:{1} 的 {0} 参数重载必须确实具有一个指定为默认重载的方法,方法是使用特性 Windows.Foundation.Metadata.DefaultOverloadAttribute 对其进行修饰。

CsWinRT1021

方法“{0}”具有参数“{1}”,该参数是数组,并且具有 System.Runtime.InteropServices.InAttribute 或 System.Runtime.InteropServices.OutAttribute。 在 Windows 运行时中,数组参数必须具有 ReadOnlyArray 或 WriteOnlyArray。 请删除这些属性,或使用相应的 Windows 运行时属性替换它们(如有必要)。

CsWinRT1022

方法“{0}”具有带 System.Runtime.InteropServices.InAttribute 或 System.Runtime.InteropServices.OutAttribute 的参数“{1}”。Windows 运行时不支持使用 System.Runtime.InteropServices.InAttribute 或 System.Runtime.InteropServices.OutAttribute 标记参数。 请考虑删除 System.Runtime.InteropServices.InAttribute,并改为使用“out”修饰符替换 System.Runtime.InteropServices.OutAttribute。

CsWinRT1023

方法“{0}”具有参数“{1}”,该参数是数组,且具有 ReadOnlyArray 和 WriteOnlyArray。 在 Windows 运行时中,数组参数内容必须是可读或可写。 请从“{1}”中删除其中一个属性。

CsWinRT1024

方法“{0}”具有输出参数“{1}”,该参数是数组,但具有 ReadOnlyArray 特性。 在 Windows 运行时中,可写入输出数组的内容。 请从“{1}”中删除该属性。

CsWinRT1025

方法“{0}”具有参数“{1}”,该参数是数组。 在 Windows 运行时中,数组参数的内容必须是可读或可写。 请将 ReadOnlyArray 或 WriteOnlyArray 应用于“{1}”。

CsWinRT1026

方法“{0}”具有参数“{1}”,该参数不是数组,并且具有 ReadOnlyArray 特性或 WriteOnlyArray 特性。 Windows 运行时不支持使用 ReadOnlyArray 或 WriteOnlyArray 标记非数组参数。

输出文件的命名空间错误和无效名称

在 Windows 运行时中,Windows 元数据 (.winmd) 文件中的所有公共类型必须在一个共享 .winmd 文件名的命名空间中,或在该文件名的子命名空间中。 例如,如果你的 Visual Studio 项目名称为 A.B(即,Windows 运行时组件为 A.B.winmd),它可以包含公共类 A.B.Class1 和 A.B.C.Class2,但无法包含 A.Class3 或 D.Class4。

注意

这些限制仅适用于公共类型,不适用于在实现中使用的私有类型。

对于 A.Class3,你可以将 Class3 移动到其他命名空间或将 Windows 运行时组件的名称更改为 A.winmd。 在之前的示例中,调用 A.B.winmd 的代码将无法找到 A.Class3。

对于 D.Class4,没有任何文件名可以包含 D.Class4 和 A.B 命名空间中的类,因此不可选择更改 Windows 运行时组件的名称。 你可以将 D.Class4 移到其他命名空间,或将其置于其他 Windows 运行时组件中。

文件系统无法区分大小写,因此使用大小写区分的命名空间将不受允许 (CsWinRT1002)。

错误号

消息正文

CsWinRT1001

公共类型具有不与其他命名空间(“{0}”)共享通用前缀的命名空间(“{1}”)。 Windows 元数据文件中的所有类型必须存在于由文件名暗示的命名空间的子命名空间中。

CsWinRT1002

找到多个名为“{0}”的命名空间;在 Windows 运行时中,命名空间名称不能仅因大小写而不同。

导出不是有效的 Windows 运行时类型的类型

组件的公共接口必须仅公开 Windows 运行时类型。 但是,.NET 为许多在 .NET 和 Windows 运行时中稍有不同的常用类型提供映射。 这使 .NET 开发人员可以使用熟悉的类型,而无需了解新类型。 你可以在组件的公共接口中使用这些映射的 .NET Framework 类型。 有关详细信息,请参阅在 Windows 运行时组件中声明类型将 Windows 运行时类型传递到托管代码Windows 运行时类型的 .NET 映射

其中许多映射都是接口。 例如,IList<T> 映射到 Windows 运行时接口 IVector<T>。 如果将 List<string> 而非 IList<string> 用作参数类型,C#/WinRT 会提供包括所有由 List<T> 实现的映射接口的备用项列表。 如果使用嵌套的泛型类型,如 List<Dictionary<int, string>>,C#/WinRT 将针对每个嵌套级别提供选择。 这些列表会非常长。

通常情况下,最好选择最接近类型的接口。 例如,对于 Dictionary<int, string>,最好选择最接近的 IDictionary<int, string>。

错误号

消息正文

CsWinRT1006

成员“{0}”的签名中包含类型“{1}”。 类型“{1}”不是有效的 Windows 运行时类型。 然而,该类型(或其泛型参数)实现的接口是有效的 Windows 运行时类型。 请考虑将成员签名中的类型“{1}”从 System.Collections.Generic 更改为以下类型之一:{2}。

在 Windows 运行时中,成员签名中的数组必须是一维数组,并且下限为 0(零)。 不允许使用嵌套数组类型,如 myArray[][] (CsWinRT1017) 和 myArray[,] (CsWinRT1018)。

注意

此限制不适用于在实现内部使用的数组。

错误号

消息正文

CsWinRT1017

方法“{0}”在其签名中具有类型“{1}”的嵌套数组。 Windows 运行时方法签名中的数组无法嵌套。

CsWinRT1018

方法“{0}”在其签名中具有类型“{1}”的多维数组。 Windows 运行时方法签名中的数组必须是一维数组。

包含禁止类型的字段的结构

在 Windows 运行时中,结构仅可以包含字段,并仅结构可以包含字段。 这些字段必须是公共字段。 有效字段类型包括枚举、结构和基元类型。

错误号

消息正文

CsWinRT1007

结构 {0} 不包含公共字段。 Windows 运行时结构必须包含至少一个公共字段。

CsWinRT1011

结构 {0} 具有非公共字段。 对于 Windows 运行时结构,所有字段都必须是公共字段。

CsWinRT1012

结构 {0} 具有常量字段。 常量只能出现在 Windows 运行时枚举中。

CsWinRT1013

结构 {0} 具有一个类型为“{1}”的字段;“{1}”不是有效的 Windows 运行时字段类型。 Windows 运行时结构中的每个字段仅可以是 UInt8、Int16、UInt16、Int32、UInt32、Int64、UInt64、单精度、双精度、布尔值、字符串、Enum,或其本身就是结构。

参数名称与生成的代码冲突

在 Windows 运行时中,将返回值视为输出参数,并且参数名称必须唯一。 默认情况下,C#/WinRT 为返回值提供名称 __retval。 如果方法具有名为 __retval 的参数,你将收到错误 CsWinRT1010。 若要更正此错误,请为参数指定一个非 __retvalue 的名称。

错误号

消息正文

CsWinRT1010

方法 {0} 中的参数名 {1} 与生成的 C#/WinRT 互操作中使用的返回值参数名相同;请使用不同的参数名称。

杂项

C#/WinRT 创作组件中的其他限制包括:

  • 不能对公共类型公开重载的运算符。
  • 类和接口不能是泛型的。
  • 类必须是封装的。
  • 参数不能通过引用传递,例如使用 ref 关键字。
  • 属性必须具有公共 get 方法。
  • 组件的命名空间中必须至少有一个公共类型(类或接口)。

错误号

消息正文

CsWinRT1014

“{0}”是运算符重载。 托管的类型无法在 Windows 运行时中公开运算符重载。

CsWinRT1004

{0} 是泛型类型。 Windows 运行时类型不能为泛型。

CsWinRT1005

CsWinRT 中不支持导出非封装类型。 请将类型 {0} 标记为“已封装”。

CsWinRT1020

方法“{0}”的参数“{1}”标记为“引用”。 Windows 运行时中不允许使用引用参数。

CsWinRT1000

属性“{0}”没有公共 getter 方法。 Windows 运行时不支持仅限 setter 的属性。

CsWinRT1003

Windows 运行时组件必须至少具有一个公共类型

在 Windows 运行时中,一个类只能有一个带有给定数量的参数的构造函数。 例如,不能是一个构造函数具有类型 String 的单个参数,而另一个构造函数具有类型 int 的单个参数。唯一的解决方法是对每个构造函数使用不同数量的参数。

错误号

消息正文

CsWinRT1009

在 Windows 运行时中,类不能有多个相同元数的构造函数;类 {0} 具有多个 {1} 元数构造函数。