Есть ли способ определить, построен ли универсальный тип из определенного определения универсального типа? - PullRequest
4 голосов
/ 22 сентября 2010

У меня есть общий метод:

Func<IEnumerable<T>, bool> CreateFunction<T>()

, где T может быть любым количеством различных типов.Этот метод делает кучу вещей, используя отражение, и если T является IDictionary, независимо от значений словаря TKey и TValue, мне нужно выполнить специальный код словаря.

Таким образом, метод можетбыть вызванным:

var f = CreateFunction<string>();
var f0 = CreateFunction<SomePocoType>();
var f1 = CreateFunction<IDictionary<string,object>>();
var f2 = CreateFunction<Dictionary<string,object>>();
var f3 = CreateFunction<SomeDerivedDictionaryType<string,object>>();

и т. д.

Уточнение по @ ответу Энди

В конечном счете, я хочу знать, наследуется ли T от / ImplementsIDictionary, даже если сам T равен Dictionary или некоторому другому типу, производному от этого интерфейса.

if(typeof(T) == typeof(IDictionary<,>)

не работает, поскольку T является универсальным типом, а не определением универсального типа.

И не зная TKey и TValue (которые не известны во время компиляции), я не могу провести сравнение с каким-либо конкретным типом, о котором я знал бы до времени выполнения.

Единственное, что я придумал, - это посмотреть на имя типа или проверить его метод с помощью отражения, найти методы, которые заставили бы меня поверить, что это словарь (то есть искать ContainsKey и get_Item).

Есть ли прямолинейностьПервый способ сделать такое определение?

Ответы [ 4 ]

7 голосов
/ 22 сентября 2010

Вы можете избежать использования уродливой и потенциально рискованной проверки строки имени типа, используя IsGenericType и GetGenericTypeDefinition , следующим образом:

var type = typeof (T);
if (typeof (IDictionary).IsAssignableFrom(type))
{
    //non-generic dictionary
}
else if (type.IsGenericType &&
         type.GetGenericTypeDefinition() == typeof (IDictionary<,>))
{
    //generic dictionary interface
}
else if (type.GetInterfaces().Any(
            i => i.IsGenericType &&
                 i.GetGenericTypeDefinition() == typeof (IDictionary<,>)))
{
    //implements generic dictionary
}
4 голосов
/ 22 сентября 2010

Простой способ заключается в следующем:

Type iDict = null;
if (typeof(T).GetGenericTypeDefinition() == typeof(IDictionary<,>))
    iDict = typeof(T);
else
    iDict = typeof(T).GetInterface(typeof(IDictionary<,>).Name);
if (iDict != null)
{
    var genericParams = iDict.GetGenericArguments();
    Type tKey = genericParams[0], tValue = genericParams[1];
}

Обратите внимание, что это не сработает (выдает исключение), если T реализует более одного IDictionary<,> интерфейса, ноэто, вероятно, подойдет для ваших целей.

Для полноты, вот реализация, в которой будет работать с типами с несколькими IDictionary<,> интерфейсами, используя первый:

Type iDict = t.GetType().GetInterfaces()
              .Where(t => t.IsGenericType
               && t.GetGenericTypeDefinition() == typeof(IDictionary<,>))
              .FirstOrDefault();
if (iDict != null)
{
    var genericParams = iDict.GetGenericArguments();
    Type tKey = genericParams[0], tValue = genericParams[1];
}

Обратите внимание, что в этой второй подпрограмме t является объектом, тогда как T является типом в первой подпрограмме.

2 голосов
/ 22 сентября 2010

Вы могли бы сделать что-то вроде

class Program
{
    static void Main(string[] args)
    {
        Example<IDictionary<int, string>>.IsDictionary();

        Example<SortedDictionary<int, string>>.IsDictionary();

        Example<Dictionary<int, string>>.IsDictionary();

        Console.ReadKey();
    }
}

public class Example<T>
{
    public static void IsDictionary()
    {
        if (typeof(T).GetInterface(typeof(IDictionary<,>).Name) != null || typeof(T).Name.Contains("IDictionary"))
        {
            Console.WriteLine("Is IDictionary");
        }
        else
        {
            Console.WriteLine("Not IDictionary");
        }
    }
}
0 голосов
/ 22 сентября 2010

Я думаю, что если вы вызовете Type.GetGenericTypeDefinition () , это должно вернуть "базовый" универсальный тип, используемый для создания конкретного типа.

Обратите внимание, что простого сравнения с IDictionary<,>, вероятно, недостаточно, потому что, если кто-то передает экземпляр Dictionary<,>, я предполагаю, что вы также захотите использовать это. Вы можете либо проверить, реализует ли Type IDictionary<,>, либо вы можете вызвать Type.IsAssignableFrom () , хотя на основании документа я не уверен, насколько хорошо это будет работать с универсальными типами. .

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