Is there a way to determine if a generic type is built from a specific generic type definition?

后端 未结 4 1337
忘掉有多难
忘掉有多难 2020-12-18 08:45

I\'ve got a generic method:

Func, bool> CreateFunction()

where T can be any number of diff

相关标签:
4条回答
  • 2020-12-18 09:17

    You could do something like

    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 讨论(0)
  • 2020-12-18 09:19

    You can avoid using ugly and potentially risky type name string checking using the IsGenericType and GetGenericTypeDefinition members, as follows:

    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
    }
    
    0 讨论(0)
  • 2020-12-18 09:21

    The easy way is just this:

    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];
    }
    

    Note that this will not work (throws an exception) if T implements more than one IDictionary<,> interface, but that will probably be fine for your purposes.

    For the sake of completeness, here's an implementation that will work on types with multiple IDictionary<,> interfaces by using the first one:

    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];
    }
    

    Note that in this second routine t is an object, whereas T is a type in the first routine.

    0 讨论(0)
  • 2020-12-18 09:28

    I think that if you call Type.GetGenericTypeDefinition() that should return the "base" generic type used to construct the concrete Type.

    Note that just comparing this to IDictionary<,> is likely not enough, because if someone passes in an instance of Dictionary<,> I assume you would want to use that, as well. You could either check to see if the Type implements IDictionary<,> or you might be able to call Type.IsAssignableFrom(), although based on the doc I'm not sure how well this would work with generic Types.

    0 讨论(0)
提交回复
热议问题