public static int GetHashCodeFor(TypeReference obj)
        {
            // a very good prime number
            const int hashCodeMultiplier = 486187739;
            // prime numbers
            const int genericInstanceTypeMultiplier = 31;
            const int byReferenceMultiplier         = 37;
            const int pointerMultiplier             = 41;
            const int requiredModifierMultiplier    = 43;
            const int optionalModifierMultiplier    = 47;
            const int pinnedMultiplier   = 53;
            const int sentinelMultiplier = 59;

            var metadataType = obj.MetadataType;

            if (metadataType == MetadataType.GenericInstance)
            {
                var genericInstanceType = (GenericInstanceType)obj;
                var hashCode            = GetHashCodeFor(genericInstanceType.ElementType) * hashCodeMultiplier + genericInstanceTypeMultiplier;
                for (var i = 0; i < genericInstanceType.GenericArguments.Count; i++)
                {
                    hashCode = hashCode * hashCodeMultiplier + GetHashCodeFor(genericInstanceType.GenericArguments[i]);
                }
                return(hashCode);
            }

            if (metadataType == MetadataType.Array)
            {
                var arrayType = (ArrayType)obj;
                return(GetHashCodeFor(arrayType.ElementType) * hashCodeMultiplier + arrayType.Rank.GetHashCode());
            }

            if (metadataType == MetadataType.Var || metadataType == MetadataType.MVar)
            {
                var genericParameter = (GenericParameter)obj;
                var hashCode         = genericParameter.Position.GetHashCode() * hashCodeMultiplier + ((int)metadataType).GetHashCode();

                var ownerTypeReference = genericParameter.Owner as TypeReference;
                if (ownerTypeReference != null)
                {
                    return(hashCode * hashCodeMultiplier + GetHashCodeFor(ownerTypeReference));
                }

                var ownerMethodReference = genericParameter.Owner as MethodReference;
                if (ownerMethodReference != null)
                {
                    return(hashCode * hashCodeMultiplier + MethodReferenceComparer.GetHashCodeFor(ownerMethodReference));
                }

                throw new InvalidOperationException("Generic parameter encountered with invalid owner");
            }

            if (metadataType == MetadataType.ByReference)
            {
                var byReferenceType = (ByReferenceType)obj;
                return(GetHashCodeFor(byReferenceType.ElementType) * hashCodeMultiplier * byReferenceMultiplier);
            }

            if (metadataType == MetadataType.Pointer)
            {
                var pointerType = (PointerType)obj;
                return(GetHashCodeFor(pointerType.ElementType) * hashCodeMultiplier * pointerMultiplier);
            }

            if (metadataType == MetadataType.RequiredModifier)
            {
                var requiredModifierType = (RequiredModifierType)obj;
                var hashCode             = GetHashCodeFor(requiredModifierType.ElementType) * requiredModifierMultiplier;
                hashCode = hashCode * hashCodeMultiplier + GetHashCodeFor(requiredModifierType.ModifierType);
                return(hashCode);
            }

            if (metadataType == MetadataType.OptionalModifier)
            {
                var optionalModifierType = (OptionalModifierType)obj;
                var hashCode             = GetHashCodeFor(optionalModifierType.ElementType) * optionalModifierMultiplier;
                hashCode = hashCode * hashCodeMultiplier + GetHashCodeFor(optionalModifierType.ModifierType);
                return(hashCode);
            }

            if (metadataType == MetadataType.Pinned)
            {
                var pinnedType = (PinnedType)obj;
                return(GetHashCodeFor(pinnedType.ElementType) * hashCodeMultiplier * pinnedMultiplier);
            }

            if (metadataType == MetadataType.Sentinel)
            {
                var sentinelType = (SentinelType)obj;
                return(GetHashCodeFor(sentinelType.ElementType) * hashCodeMultiplier * sentinelMultiplier);
            }

            if (metadataType == MetadataType.FunctionPointer)
            {
                throw new NotImplementedException("We currently don't handle function pointer types.");
            }

            return(obj.Namespace.GetHashCode() * hashCodeMultiplier + obj.FullName.GetHashCode());
        }
        static bool AreEqual(GenericParameter a, GenericParameter b, TypeComparisonMode comparisonMode = TypeComparisonMode.Exact)
        {
            if (ReferenceEquals(a, b))
            {
                return(true);
            }

            if (a.Position != b.Position)
            {
                return(false);
            }

            if (a.Type != b.Type)
            {
                return(false);
            }

            var aOwnerType = a.Owner as TypeReference;

            if (aOwnerType != null && AreEqual(aOwnerType, b.Owner as TypeReference, comparisonMode))
            {
                return(true);
            }

            var aOwnerMethod = a.Owner as MethodReference;

            if (aOwnerMethod != null && comparisonMode != TypeComparisonMode.SignatureOnlyLoose && MethodReferenceComparer.AreEqual(aOwnerMethod, b.Owner as MethodReference))
            {
                return(true);
            }

            return(comparisonMode == TypeComparisonMode.SignatureOnly || comparisonMode == TypeComparisonMode.SignatureOnlyLoose);
        }