Рефлексивное общее обнаружение - PullRequest
0 голосов
/ 14 мая 2010

Попытка выяснить, имеет ли предоставленный Type заданный универсальный тип (с любыми универсальными типами внутри)

Позвольте мне объяснить:

bool IsOfGenericType(Type baseType, Type sampleType)
{
    /// ...
}

такой, что:

IsOfGenericType(typeof(Dictionary<,>), typeof(Dictionary<string, int>)); // True
IsOfGenericType(typeof(IDictionary<,>), typeof(Dictionary<string, int>)); // True
IsOfGenericType(typeof(IList<>), typeof(Dictionary<string,int>)); // False

Тем не менее, я играл с некоторым отражением в промежуточном окне, вот мои результаты:

typeof(Dictionary<,>) is typeof(Dictionary<string,int>)
Type expected
typeof(Dictionary<string,int>) is typeof(Dictionary<string,int>)
Type expected
typeof(Dictionary<string,int>).IsAssignableFrom(typeof(Dictionary<,>))
false
typeof(Dictionary<string,int>).IsSubclassOf(typeof(Dictionary<,>))
false
typeof(Dictionary<string,int>).IsInstanceOfType(typeof(Dictionary<,>))
false
typeof(Dictionary<,>).IsInstanceOfType(typeof(Dictionary<string,int>))
false
typeof(Dictionary<,>).IsAssignableFrom(typeof(Dictionary<string,int>))
false
typeof(Dictionary<,>).IsSubclassOf(typeof(Dictionary<string,int>))
false
typeof(Dictionary<,>) is typeof(Dictionary<string,int>)
Type expected
typeof(Dictionary<string,int>) is typeof(Dictionary<string,int>)
Type expected
typeof(Dictionary<string,int>).IsAssignableFrom(typeof(Dictionary<,>))
false
typeof(Dictionary<string,int>).IsSubclassOf(typeof(Dictionary<,>))
false
typeof(Dictionary<string,int>).IsInstanceOfType(typeof(Dictionary<,>))
false
typeof(Dictionary<,>).IsInstanceOfType(typeof(Dictionary<string,int>))
false
typeof(Dictionary<,>).IsAssignableFrom(typeof(Dictionary<string,int>))
false
typeof(Dictionary<,>).IsSubclassOf(typeof(Dictionary<string,int>))
false

Так что теперь я в растерянности, потому что когда вы смотрите на base.Name на typeof (Dictionary), вы получаете

Dictionary`2

Что совпадает с typeof(Dictionary<,>).Name

1 Ответ

3 голосов
/ 14 мая 2010

Сначала я подумал, что это должно работать:

bool IsOfGenericType(Type baseType, Type sampleType) { 
  return baseType.IsAssignableFrom(sampleType.GetGenericTypeDefinition());
} 

Метод GetGenericTypeDefinition возвращает версию типа без указанных общих параметров. Например, для типа List<int> он даст вам List<>.

Но, к сожалению, это не совсем работает, потому что определения универсальных типов нельзя назначать друг другу (потому что они не являются реальными типами, которые вы могли бы использовать где-либо в вашем коде). Метод IsAssignableFrom работает только для реальных типов. Это означает, что нам нужно сделать дополнительный шаг и указать некоторые параметры типа обратно в определения универсального типа, и затем мы можем проверить, можно ли их назначить.

Вы можете заполнить параметры типа с помощью System.Object и затем сравнить их:

Type SpecifyObjectArgs(Type sample) {
  var types = new Type[sample.GetGenericArguments().Length];
  for(int i = 0; i < types.Length; i++) types[i] = typeof(System.Object);
  return sample.MakeGenericType(types);
}

var baseWithObjs = SpecifyObjectArgs(baseType);
var sampleWithObjs = SpecifyObjectArgs(sampleType.GetGenericTypeDefinition());
baseWithObjs.IsAssignableFrom(sampleWithObjs);

Возвращает определение универсального типа к нормальному типу, поэтому вы получите, например, IList<Object> и List<Object>, которые можно легко протестировать с помощью IsAssignableFrom.

[Есть еще некоторые ограничения - см. Комментарии]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...