How to compare two generic "Type" variables?

I'm confused... I have no idea why this particular problem is occurring and I was wondering if someone could shed some light on the subject. I'm doing some reflection operations which requires a lot of Type comparisons - as such I'm storing some information with the "Type" as the key...

However, it seems two of my types, even though they seem superficially the same, are not actually the same as it's throwing a "Key Not Found" exception when I try to look it up.

Here's a screenshot of my inspector:

enter image description here

Is there some detail about comparing underlying types I might be missing?

EDIT: In accordance with Mr. Skeet's request, here is the underlying class that is supposed to generate the entire type tree of an object. It's somewhat messy, as I've been futzing with it too much - you can see here that the same "Type" object is added to both "myType" and "myTypeTypes" - so I have no idea why they're suddenly becoming different objects...

 public class TypeTree
    {
        private Type original;
        private TypeTree subTree;
        private Dictionary<Type, List<Type>> subTreeTypes = new Dictionary<Type, List<Type>>();
        private List<Type> myTypes = new List<Type>();
        private Dictionary<Type, List<Type>> myTypeTypes = new Dictionary<Type, List<Type>>();


        public TypeTree(Type Next)
        {
            original = Next;
            if (Next.IsGenericType)
            {
                myTypes.Add(Next.GetGenericTypeDefinition());
                Type[] genTypes = Next.GetGenericArguments();
                subTreeTypes.Add(Next.GetGenericTypeDefinition(), new List<Type>(genTypes));
            }
            else
            {
                myTypes.Add(Next);

            }

            Type[] lis = Next.GetInterfaces();
            foreach (var v in lis)
            {                    
                if (v.IsGenericType)
                {
                    Type genType = v.GetGenericTypeDefinition();
                    myTypes.Add(genType);                       
                    Type[] genTypes = v.GetGenericArguments();
                    myTypeTypes.Add(genType, new List<Type>());
                    myTypeTypes[genType].AddRange(genTypes);
                }
                else
                {
                    myTypes.Add(v);
                }
            }
            try
            {
                subTree = new TypeTree(Next.BaseType, myTypes, myTypeTypes, subTreeTypes, Next);
            }
            catch (NullReferenceException ex)
            {

            }
        }

        private TypeTree(Type Next, List<Type> MyList, Dictionary<Type, List<Type>> MyTypeTypes, Dictionary<Type, List<Type>> SubTreeTypes, Type Original)
        {

            if (Next.IsGenericType || Next.IsGenericTypeDefinition)
            {
                MyList.Add(Next.GetGenericTypeDefinition());
                Type[] genTypes = Next.GetGenericArguments();
                SubTreeTypes.Add(Next.GetGenericTypeDefinition(), new List<Type>(genTypes));
            }
            else
            {
                MyList.Add(Next);
                SubTreeTypes.Add(Next, new List<Type>(Original.GetGenericArguments()));
            }
            Type[] lis = Next.GetInterfaces();
            foreach (var v in lis)
            {
                if (v.IsGenericType)
                {
                    Type genType = v.GetGenericTypeDefinition();
                    MyList.Add(genType);
                    Type[] genTypes = v.GetGenericArguments();                        
                    MyTypeTypes.Add(genType, new List<Type>());
                    MyTypeTypes[genType].AddRange(genTypes);
                }
                else
                {
                    myTypes.Add(v);
                }
            }
            try
            {
                subTree = new TypeTree(Next.BaseType, myTypes, MyTypeTypes, SubTreeTypes, Original);
            }
            catch (NullReferenceException ex)
            {

            }
        }

        public bool ReturnBestType(Dictionary<Type, MethodInfo> Search, ref MethodInfo SelectedMethod)
        {
            bool ret = false;
            for (int i = 0; i < myTypes.Count; i++)
            {
                if (Search.ContainsKey(myTypes[i]))
                {
                    if (myTypes[i].IsGenericTypeDefinition)
                    { 
                        List<Type> Args = new List<Type>();
                        Args.Add(original);
                        Args.AddRange(myTypeTypes[myTypes[i]].ToArray());

                        MethodInfo mi = Search[myTypes[i]].MakeGenericMethod(Args.ToArray()); 
                        SelectedMethod = mi;
                        return true;
                    }
                    else
                    {
                        SelectedMethod = Search[myTypes[i]]; 
                        ret = true;
                        break;
                    }
                }
            }

            return ret;
        }
    }
Jon Skeet
people
quotationmark

I suspect you're running into a problem due to the T in ICollection<T> being different in each case. Here's a short but complete example:

using System;

interface IFoo<T> {}

public class Foo1<T> : IFoo<T> {}
public class Foo2<T> : IFoo<T> {}

class Test
{
    static void Main()
    {
        var type1 = typeof(Foo1<>).GetInterfaces()[0];
        var type2 = typeof(Foo2<>).GetInterfaces()[0];

        Console.WriteLine(type1);
        Console.WriteLine(type2);
        Console.WriteLine(type1.Equals(type2));
    }
}

Output:

IFoo`1[T]
IFoo`1[T]
False

Now you can use Type.GetGenericTypeDefinition() to effectively remove the T in each case:

Console.WriteLine(type1.GetGenericTypeDefinition()
    .Equals(type2.GetGenericTypeDefinition())); // True

... but it's unclear whether that helps in your real use case.

people

See more on this question at Stackoverflow