有没有办法确定泛型类型是否是从特定的泛型类型定义构建的?

时间:2010-09-22 02:11:58

标签: c# generics reflection types

我有一个通用的方法:

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

其中T可以是任意数量的不同类型。这个方法使用反射做了很多东西,如果TIDictionary,无论字典的TKeyTValue我需要执行字典特定的代码。

因此可以调用该方法:

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>>();

根据@Andy的答案澄清

最终我想知道T是否继承自/ IDictionary,即使T本身是Dictionary,也可能是从该接口派生的其他类型。

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

不起作用,因为T是泛型类型而不是泛型类型定义。

在不知道TKeyTValue(编译时不知道)的情况下,我无法与运行时知道的任何具体类型进行比较。

我唯一想到的就是查看类型的名称或使用反射检查其方法,寻找可以让我相信它是字典的方法(即查找ContainsKey和{ {1}})。

有没有直接的方法来做出这种决定?

4 个答案:

答案 0 :(得分:7)

您可以避免使用IsGenericTypeGetGenericTypeDefinition成员使用丑陋且具有潜在风险的类型名称字符串检查,如下所示:

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
}

答案 1 :(得分:4)

简单的方法就是:

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 :(得分:2)

您可以执行类似

的操作
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");
        }
    }
}

答案 3 :(得分:0)

我认为如果你调用Type.GetGenericTypeDefinition()应该返回用于构造具体类型的“基础”泛型类型。

请注意,仅将此与IDictionary<,>进行比较可能还不够,因为如果有人传入Dictionary<,>的实例,我认为您也希望使用它。您可以检查Type是否实现IDictionary<,>,或者您可以调用Type.IsAssignableFrom(),尽管根据文档,我不确定这对于泛型类型有多好。