static bool TypeEquals (Type a, Type b) {
if (a == b)
return true;
if (a.HasElementType) {
if (!b.HasElementType)
return false;
if (!TypeEquals (a.GetElementType (), b.GetElementType ()))
return false;
if (a.IsArray) {
if (!b.IsArray)
return false;
int rank = a.GetArrayRank ();
if (rank != b.GetArrayRank ())
return false;
if (rank == 1 && IsBoundedVector (a) != IsBoundedVector (b))
return false;
} else if (a.IsByRef) {
if (!b.IsByRef)
return false;
} else if (a.IsPointer) {
if (!b.IsPointer)
return false;
}
return true;
}
if (a.IsGenericType) {
if (!b.IsGenericType)
return false;
if (a.IsGenericParameter)
return a == b;
if (a.IsGenericParameter) //previous test should have caught it
return false;
if (a.IsGenericTypeDefinition) {
if (!b.IsGenericTypeDefinition)
return false;
} else {
if (b.IsGenericTypeDefinition)
return false;
if (!TypeEquals (a.GetGenericTypeDefinition (), b.GetGenericTypeDefinition ()))
return false;
Type[] argsA = a.GetGenericArguments ();
Type[] argsB = b.GetGenericArguments ();
for (int i = 0; i < argsA.Length; ++i) {
if (!TypeEquals (argsA [i], argsB [i]))
return false;
}
}
}
/*
Now only non-generic, non compound types are left. To properly deal with user
types we would have to call UnderlyingSystemType, but we let them have their
own instantiation as this is MS behavior and mcs (pre C# 4.0, at least) doesn't
depend on proper UT canonicalization.
*/
return a == b;
}