1

Я пытаюсь скомпилировать свой рабочий стол .NET dll для платформы WinRT (Target Windows 8.1). Он работал отлично на рабочем столе, но в проекте WinRT у меня есть эта ошибка компилятора в коде:Невозможно преобразовать тип 'System.Attribute' в общий аргумент 'T' - почему?

internal static T[] CreateRuntime<T>(MemberInfo member, bool inherit) 
{ 
    return member.GetCustomAttributes(typeof(T), inherit).Select(attr => (T)attr).ToArray(); 
} 

Я не могу бросить Attributeattr в общий аргумент T ... но почему только на WinRT? Существуют ли какие-либо различия в языке или что может вызвать это?

+0

Вы помещали ограничение 'where T: Attribute'? Определение 'T' было бы полезно увидеть – Rob

+0

Это также может быть полезно: http://www.minddriven.de/index.php/technology/dot-net/net-winrt-get-custom-attributes-from- enum-value – Rob

+0

@Rob спасибо, но мой вопрос касается различий в компиляторах - не проверка кода;) btw, когда я помещаю 'T: Attribute', ошибка исчезает. – Vlad

ответ

2

Это является следствием правил преобразования типов в C#. Из спецификации C# 5.0: Параметры

6.2.7 Явные преобразования с участием типа
Существуют следующие явные преобразования для данного параметра типа T:
• От эффективного базового класса С Т до Т и из любого базового класса C в T. Во время выполнения, если T является типом значения, преобразование выполняется как преобразование unboxing. В противном случае преобразование выполняется как явное преобразование ссылок или преобразование идентичности.

[& hellip; есть три точки пули, но ни один не применять здесь и hellip;]

Приведенные выше правила не допускают прямого явного преобразования из неограниченного параметра типа к типу не-интерфейс, который может быть удивительно , Причина этого правила заключается в том, чтобы предотвратить путаницу и сделать семантику таких преобразований понятными.

Безграничных, единственные известный базовый класс 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, вы не можете отлиты из не-базового класса 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 в T.


Обратите внимание, что это не разница в реализации языка между .NET и WinRT. Это те же самые правила C#. Это просто, что вы на самом деле имеете дело с различными реализациями GetCustomeAttributes(), где возвращаемые значения различны, что делает тип вашей переменной attr другой и, таким образом, дает разные результаты в каждом случае.


Показать похожие вопросы:

Cannot convert type 'System.Windows.Forms.Control' to 'T'
C# Problem with Generics
Casting to generic type fails in c#

Я был разочарован тем, что ни один из этих иначе релевантных вопросов и ответов, адресованных ядро ​​вопроса, который почему C# делает это требование. Я попытался сделать это выше. Тем не менее, они все охватывают похожие сценарии, показывая, как то же самое может случиться в контексте кода, отличного от Winrt. Они также иллюстрируют два основных решения:

  1. Используйте ограничение на общий параметр (как я предлагаю здесь)
  2. Cast для object перед заливкой в ​​T. Это обходит общее преобразование, удаляя контекст, чтобы компилятор разрешал выполнение. ИМХО это гораздо менее предпочтительно; но если вы не можете добавить ограничение по какой-либо причине (например, вы имеете дело со специальным случаем, который не применяется ко всем возможным T & hellip, однако нежелательны такие реализации), это будет работать.