+ public static bool IsEqualGenericType (Type a, Type b)
+ {
+ if ((a is TypeBuilder) && a.IsGenericTypeDefinition && b.IsGenericInstance) {
+ //
+ // `a' is a generic type definition's TypeBuilder and `b' is a
+ // generic instance of the same type.
+ //
+ // Example:
+ //
+ // class Stack<T>
+ // {
+ // void Test (Stack<T> stack) { }
+ // }
+ //
+ // The first argument of `Test' will be the generic instance
+ // "Stack<!0>" - which is the same type than the "Stack" TypeBuilder.
+ //
+ if (a != b.GetGenericTypeDefinition ())
+ return false;
+
+ Type[] aparams = a.GetGenericArguments ();
+ Type[] bparams = b.GetGenericArguments ();
+
+ if (aparams.Length != bparams.Length)
+ return false;
+
+ for (int i = 0; i < aparams.Length; i++)
+ if (!aparams [i].Equals (bparams [i]))
+ return false;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public static bool IsEqual (Type a, Type b)
+ {
+ if (a.Equals (b))
+ return true;
+ else
+ return IsEqualGenericType (a, b);
+ }
+
+ public static bool MayBecomeEqualGenericTypes (Type a, Type b)
+ {
+ if (a.IsGenericParameter) {
+ //
+ // If a is an array of a's type, they may never
+ // become equal.
+ //
+ while (b.IsArray) {
+ b = b.GetElementType ();
+ if (a.Equals (b))
+ return false;
+ }
+
+ //
+ // If b is a generic parameter or an actual type,
+ // they may become equal:
+ //
+ // class X<T,U> : I<T>, I<U>
+ // class X<T> : I<T>, I<float>
+ //
+ if (b.IsGenericParameter || !b.IsGenericInstance)
+ return true;
+
+ //
+ // We're now comparing a type parameter with a
+ // generic instance. They may become equal unless
+ // the type parameter appears anywhere in the
+ // generic instance:
+ //
+ // class X<T,U> : I<T>, I<X<U>>
+ // -> error because you could instanciate it as
+ // X<X<int>,int>
+ //
+ // class X<T> : I<T>, I<X<T>> -> ok
+ //
+
+ Type[] bargs = GetTypeArguments (b);
+ for (int i = 0; i < bargs.Length; i++) {
+ if (a.Equals (bargs [i]))
+ return false;
+ }
+
+ return true;
+ }
+
+ if (b.IsGenericParameter)
+ return MayBecomeEqualGenericTypes (b, a);
+
+ //
+ // At this point, neither a nor b are a type parameter.
+ //
+ // If one of them is a generic instance, let
+ // MayBecomeEqualGenericInstances() compare them (if the
+ // other one is not a generic instance, they can never
+ // become equal).
+ //
+
+ if (a.IsGenericInstance || b.IsGenericInstance)
+ return MayBecomeEqualGenericInstances (a, b);
+
+ //
+ // If both of them are arrays.
+ //
+
+ if (a.IsArray && b.IsArray) {
+ if (a.GetArrayRank () != b.GetArrayRank ())
+ return false;
+
+ a = a.GetElementType ();
+ b = b.GetElementType ();
+
+ return MayBecomeEqualGenericTypes (a, b);
+ }
+
+ //
+ // Ok, two ordinary types.
+ //
+
+ return a.Equals (b);
+ }
+
+ //
+ // Checks whether two generic instances may become equal for some
+ // particular instantiation (26.3.1).
+ //
+ public static bool MayBecomeEqualGenericInstances (Type a, Type b)
+ {
+ if (!a.IsGenericInstance || !b.IsGenericInstance)
+ return false;
+ if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
+ return false;
+
+ Type[] aargs = GetTypeArguments (a);
+ Type[] bargs = GetTypeArguments (b);
+
+ if (aargs.Length != bargs.Length)
+ return false;
+
+ for (int i = 0; i < aargs.Length; i++) {
+ if (MayBecomeEqualGenericTypes (aargs [i], bargs [i]))
+ return true;
+ }
+
+ return false;
+ }
+
+ public static bool IsSubclassOf (Type type, Type parent)
+ {
+ if (type.IsGenericInstance && !parent.IsGenericInstance)
+ type = type.GetGenericTypeDefinition ();
+
+ return type.IsSubclassOf (parent);
+ }
+