C# 无法将类型“System.Attribute”转换为泛型参数“T”-为什么?

C# 无法将类型“System.Attribute”转换为泛型参数“T”-为什么?,c#,compiler-errors,windows-runtime,windows-8.1,system.reflection,C#,Compiler Errors,Windows Runtime,Windows 8.1,System.reflection,我正在尝试将桌面.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(); }

我正在尝试将桌面.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();
}

我无法将属性attr强制转换为泛型参数t。。。但为什么只在WinRT上?语言上是否有任何差异或是什么原因导致了这种情况?

这是C中类型转换规则的结果。与C 5.0规范不同:

6.2.7涉及类型参数的显式转换 给定类型参数T存在以下显式转换: •从T的有效基类C到T,以及从C的任何基类到T。在运行时,如果T是值类型,则转换作为取消装箱转换执行。否则,转换将作为显式引用转换或标识转换执行。 […还有三个要点,但都不适用于此处…] 上述规则不允许从无约束类型参数直接显式转换为非接口类型,这可能令人惊讶。此规则的原因是为了防止混淆,并明确此类转换的语义

不受约束,T的唯一已知基类是System.Object。但是在Winrt中,GetCustomAttributes方法返回IEnumerable。因此,变量attr具有type属性,而不是object

因此,当您使用.NETAPI时,可以从基类对象强制转换为T,但当您使用Winrt时,不能从非基类属性强制转换为T

您可以通过向方法声明添加约束来更改T的已知基类:

internal static T[] CreateRuntime<T>(MemberInfo member, bool inherit)
    where T : Attribute
{
    return member.GetCustomAttributes(typeof(T), inherit).Select(attr => (T)attr).ToArray();
}
随着T的基类现在被声明为Attribute,您现在可以从Attribute转换为T

请注意,.NET和Winrt之间在语言实现上没有区别。这和C规则完全一样。很简单,您实际上正在处理GetCustomeAttributes的不同实现,其中返回值不同,使变量attr的类型不同,从而在每种情况下产生不同的结果

见相关问题:

我感到失望的是,这些其他相关的问题和答案都没有解决问题的核心,这就是为什么C提出这一要求。我在上面已经试过了。然而,它们都涵盖了类似的场景,展示了在非Winrt代码的上下文中如何发生相同的事情。它们还说明了两种基本解决方案:

正如我在这里建议的那样,对泛型参数使用约束 在转换为T之前转换为对象。这将绕过泛型转换,删除上下文以便编译器允许转换。我认为这不太可取;但是,如果由于某些原因无法添加约束,例如您正在处理一个不适用于所有可能的t的特殊情况……无论这种实现多么不受欢迎,这都会起作用。
您是否将约束放在了T:Attribute的位置?T的定义很有用,这可能也很有用:@Rob谢谢,但我的问题是关于编译器的差异,而不是代码审查;顺便说一句,当我放置T:Attribute时,错误消失了。