Отражение .NET - Результаты GetInterfaces () определения универсального типа не могут быть успешно сопоставлены с универсальным литералом typeof - PullRequest
0 голосов
/ 22 января 2019

Мне недавно пришлось кое-что отразить в .NET и наткнуться на странное поведение при сравнении определений универсальных типов.

Мне пришлось решить, является ли тип IDictionary<,>, извлекая объект Typeот LINQ Expression, поэтому я не смог использовать оператор is, чтобы решить это.Кроме того, мне пришлось игнорировать параметры типа, иными словами, единственное, что было важно, это то, имел ли я дело с IDictionary<,> любого типа ключ / значение.

Я начал со следующего:

// Just a placeholder, in my code I have no way of knowing that it
// is a Dictionary of string keys and string values or even that it
// is a dictionary at all.
typeof(Dictionary<string, string>)
    .GetGenericTypeDefinition()
    .GetInterfaces()
    .Any(i => i == typeof(IDictionary<,>))

Я предполагал, что, поскольку я читал интерфейсы определения универсального типа, я получил бы определения универсального интерфейса.Еще более странным является то, что когда я вставил приведенный выше код в LINQPad, он вернул следующее:

typeof(IDictionary<TKey,TValue>) // it appears here
typeof(ICollection<KeyValuePair<TKey,TValue>>) 
typeof(IEnumerable<KeyValuePair<TKey,TValue>>) 
typeof(IEnumerable) 
typeof(IDictionary) 
typeof(ICollection) 
typeof(IReadOnlyDictionary<TKey,TValue>) 
typeof(IReadOnlyCollection<KeyValuePair<TKey,TValue>>) 
typeof(ISerializable) 
typeof(IDeserializationCallback) 

Однако по какой-то причине сравнение в методе Any не удалось ни для одного из этих элементов.Однако, если я получу определения общих типов для самих интерфейсов, например, так:

typeof(Dictionary<string, string>)
    .GetGenericTypeDefinition()
    .GetInterfaces()
    .Select(i => i.IsGenericType ? i.GetGenericTypeDefinition() : i)
    .Any(i => i == typeof(IDictionary<,>))

, тогда он вернет true, как и должно быть.

Почему это так?Разве интерфейсы, возвращаемые методом .GetInterfaces() при вызове определения общего типа, уже не являются самими определениями общего интерфейса?Если да, то каково объяснение, что когда я проверяю возвращенные интерфейсы в LINQPad, они кажутся общими определениями типов?

Я полагаю, это связано с тем фактом, что параметры типа интерфейса могут быть полностью независимы отобобщенные аргументы разработчика, например:

public class MyGenericType<TKey, TValue> : ISomeInterface<object> ...

, но все же выглядит странным, что возвращенные объекты Type, похоже, не отражают такой случай (как я ожидал в этом конкретном примере) и из«выглядит», они выглядят как определения общих типов, но не идентифицированы как таковые.

1 Ответ

0 голосов
/ 23 января 2019

CodeCaster уже дал ответ в разделе комментариев.В основном это связано с открытыми / закрытыми конструкциями.typeof(IDictionary<,>) - это не то же самое, что typeof(IDictionary<string,int>).Более того, это не то же самое, что typeof(IDictionary<TKey,TValue>).

По сути, typeof(IDictionary<,>) является несвязанным типом, а IDictionary<TKey, TValue>, который вы получаете от вашего typeof(Dictionary<string, string>).GetGenericTypeDefinition(), является открытым, но составным типом, поскольку TKey иTValue являются параметрами типа.


Итак, вот простой метод расширения, который может делать то, что вы хотите.

public static bool HasGenericInterface(this Type @type,Type genericInterface)
{
    var allInterfaces = @type.GetInterfaces();
    return allInterfaces
        .Where(i => i.IsGenericType)
        .Select(i => i.GetGenericTypeDefinition())
        .Any(i => i.IsAssignableFrom(genericInterface));
 }

Простое использование выглядит следующим образом

var result = typeof(MyClass).GetType().HasGenericInterface(typeof(IDictionary<,>));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...