我正在尝试将桌面.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上?语言有什么不同或可能导致什么原因?
答案 0 :(得分:2)
这是C#中类型转换规则的结果。来自C#5.0规范:
6.2.7涉及类型参数的显式转换
对于给定的类型参数T,存在以下显式转换:
•从T的有效基类C到T以及从C到T的任何基类。在运行时,如果T是值类型,则转换将作为拆箱转换执行。否则,转换将作为显式引用转换或标识转换执行。
[......还有其他三个要点,但这里没有一个要点......]
上述规则不允许从无约束类型参数直接显式转换为非接口类型,这可能是令人惊讶的。这条规则的原因是为了防止混淆并使这种转换的语义清晰。
无约束,T
唯一已知的基类是System.Object
。但在Winrt中,使用GetCustomAttributes()
方法is implemented as an extension method,返回IEnumerable<Attribute>
而不是返回的object[]
in the .NET API。因此,变量attr
的类型为Attribute
,而不是object
。
因此,当您使用.NET API时,可以从基类object
转换为T
,但是当您使用Winrt时,您无法从非基类转换{ {1}}至Attribute
。
您可以通过向方法声明添加约束来更改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
。
请注意,这与不 .NET和Winrt之间的语言实现存在差异。这与C#规则完全相同。简单地说,您实际上正在处理T
的不同实现,其中返回值不同,使得变量GetCustomeAttributes()
的类型不同,从而在每种情况下产生不同的结果。
查看相关问题:
Cannot convert type 'System.Windows.Forms.Control' to 'T'
C# Problem with Generics
Casting to generic type fails in c#
我很失望这些与其他相关的问题和答案都没有解决问题的核心,这就是为什么 C#提出这个要求。我试过这样做。但是,它们都涵盖了类似的场景,展示了在非Winrt代码的上下文中如何发生同样的事情。他们还说明了两个基本解决方案:
attr
,然后转换为object
。这绕过了泛型转换,删除了上下文,以便编译器允许转换。恕我直言,这是不太可取的;但是如果由于某些原因你不能添加约束(比如你正在处理一个不适用于所有可能的T
的特殊情况......但是不合适的这种实现是),这将有效。