无法将类型 'System.Attribute' 转换为泛型参数 'T' - 为什么?
Cannot convert type 'System.Attribute' to generic argument 'T' - why?
我正在尝试将我的桌面 .NET dll 编译到 WinRT 平台(目标 Windows 8.1)。它在桌面上运行良好,但在 WinRT 项目中我在代码中遇到编译器错误:
internal static T[] CreateRuntime<T>(MemberInfo member, bool inherit)
{
return member.GetCustomAttributes(typeof(T), inherit).Select(attr => (T)attr).ToArray();
}
我无法将 Attribute
attr
转换为通用参数 T
... 但为什么只在 WinRT 上?是否存在语言差异或可能导致此问题的原因?
这是 C# 中类型转换规则的结果。来自 C# 5.0 规范:
6.2.7 Explicit conversions involving type parameters
The following explicit conversions exist for a given type parameter T:
• From the effective base class C of T to T and from any base class of C to T. At run-time, if T is a value type, the conversion is executed as an unboxing conversion. Otherwise, the conversion is executed as an explicit reference conversion or identity conversion.
[…there are three other bullet points, but none apply here…]
The above rules do not permit a direct explicit conversion from an unconstrained type parameter to a non-interface type, which might be surprising. The reason for this rule is to prevent confusion and make the semantics of such conversions clear.
不受约束,T
的唯一已知基数 class 是 System.Object
。但是在Winrt中,GetCustomAttributes()
方法is implemented as an extension method, returning IEnumerable<Attribute>
instead of the object[]
that is returned in the .NET API。因此变量 attr
的类型是 Attribute
,而不是 object
.
因此,当您使用 .NET API 时,您可以从基础 class object
转换为 T
,但是当您使用 Winrt 时,您不能从非基础-class Attribute
转换为 T
.
您可以通过向方法声明添加约束来更改 T
的已知基数 class:
internal static T[] CreateRuntime<T>(MemberInfo member, bool inherit)
where T : Attribute
{
return member.GetCustomAttributes(typeof(T), inherit).Select(attr => (T)attr).ToArray();
}
由于 T
的基数 class 现在声明为 Attribute
,您现在可以从 Attribute
转换为 T
。
请注意,这是 而不是 .NET 和 Winrt 之间的语言实现差异。这是完全相同的 C# 规则。很简单,您实际上是在处理 GetCustomeAttributes()
的不同实现,其中 return 值不同,从而使变量 attr
的类型不同,从而在每种情况下产生不同的结果。
查看相关问题:
Cannot convert type 'System.Windows.Forms.Control' to 'T'
C# Problem with Generics
Casting to generic type fails in c#
令我失望的是 none 这些其他方面相关的问题和答案解决了问题的核心,即 为什么 C# 提出此要求。我在上面尝试过这样做。但是,它们确实涵盖了相似的场景,展示了在非 Winrt 代码的上下文中如何发生完全相同的事情。他们还说明了两个基本解决方案:
- 对泛型参数使用约束(正如我在此处建议的那样)
- 在转换为
T
之前转换为 object
。这绕过了泛型转换,删除了上下文,以便编译器允许转换。恕我直言,这不太可取;但是如果由于某种原因你不能添加约束(比如你正在处理一个特殊情况,它不适用于所有可能的情况T
......但是这样的实现是不受欢迎的),这将起作用。
我正在尝试将我的桌面 .NET dll 编译到 WinRT 平台(目标 Windows 8.1)。它在桌面上运行良好,但在 WinRT 项目中我在代码中遇到编译器错误:
internal static T[] CreateRuntime<T>(MemberInfo member, bool inherit)
{
return member.GetCustomAttributes(typeof(T), inherit).Select(attr => (T)attr).ToArray();
}
我无法将 Attribute
attr
转换为通用参数 T
... 但为什么只在 WinRT 上?是否存在语言差异或可能导致此问题的原因?
这是 C# 中类型转换规则的结果。来自 C# 5.0 规范:
6.2.7 Explicit conversions involving type parameters
The following explicit conversions exist for a given type parameter T:
• From the effective base class C of T to T and from any base class of C to T. At run-time, if T is a value type, the conversion is executed as an unboxing conversion. Otherwise, the conversion is executed as an explicit reference conversion or identity conversion.
[…there are three other bullet points, but none apply here…]
The above rules do not permit a direct explicit conversion from an unconstrained type parameter to a non-interface type, which might be surprising. The reason for this rule is to prevent confusion and make the semantics of such conversions clear.
不受约束,T
的唯一已知基数 class 是 System.Object
。但是在Winrt中,GetCustomAttributes()
方法is implemented as an extension method, returning IEnumerable<Attribute>
instead of the object[]
that is returned in the .NET API。因此变量 attr
的类型是 Attribute
,而不是 object
.
因此,当您使用 .NET API 时,您可以从基础 class object
转换为 T
,但是当您使用 Winrt 时,您不能从非基础-class Attribute
转换为 T
.
您可以通过向方法声明添加约束来更改 T
的已知基数 class:
internal static T[] CreateRuntime<T>(MemberInfo member, bool inherit)
where T : Attribute
{
return member.GetCustomAttributes(typeof(T), inherit).Select(attr => (T)attr).ToArray();
}
由于 T
的基数 class 现在声明为 Attribute
,您现在可以从 Attribute
转换为 T
。
请注意,这是 而不是 .NET 和 Winrt 之间的语言实现差异。这是完全相同的 C# 规则。很简单,您实际上是在处理 GetCustomeAttributes()
的不同实现,其中 return 值不同,从而使变量 attr
的类型不同,从而在每种情况下产生不同的结果。
查看相关问题:
Cannot convert type 'System.Windows.Forms.Control' to 'T'
C# Problem with Generics
Casting to generic type fails in c#
令我失望的是 none 这些其他方面相关的问题和答案解决了问题的核心,即 为什么 C# 提出此要求。我在上面尝试过这样做。但是,它们确实涵盖了相似的场景,展示了在非 Winrt 代码的上下文中如何发生完全相同的事情。他们还说明了两个基本解决方案:
- 对泛型参数使用约束(正如我在此处建议的那样)
- 在转换为
T
之前转换为object
。这绕过了泛型转换,删除了上下文,以便编译器允许转换。恕我直言,这不太可取;但是如果由于某种原因你不能添加约束(比如你正在处理一个特殊情况,它不适用于所有可能的情况T
......但是这样的实现是不受欢迎的),这将起作用。