internal static bool IdentifyImmutable(TypeModel model, Type declaredType, out MethodInfo builderFactory, out MethodInfo add, out MethodInfo addRange, out MethodInfo finish)
        {
            builderFactory = add = addRange = finish = null;
            if (model == null || declaredType == null) return false;
#if WINRT
            TypeInfo declaredTypeInfo = declaredType.GetTypeInfo();
#else
            Type declaredTypeInfo = declaredType;
#endif

            // try to detect immutable collections; firstly, they are all generic, and all implement IReadOnlyCollection<T> for some T
            if(!declaredTypeInfo.IsGenericType) return false;

#if WINRT
            Type[] typeArgs = declaredTypeInfo.GenericTypeArguments, effectiveType;
#else
            Type[] typeArgs = declaredTypeInfo.GetGenericArguments(), effectiveType;
#endif
            switch (typeArgs.Length)
            {
                case 1:
                    effectiveType = typeArgs;
                    break; // fine
                case 2:
                    Type kvp = model.MapType(typeof(System.Collections.Generic.KeyValuePair<,>));
                    if (kvp == null) return false;
                    kvp = kvp.MakeGenericType(typeArgs);
                    effectiveType = new Type[] { kvp };
                    break;
                default:
                    return false; // no clue!
            }

            if (ResolveIReadOnlyCollection(declaredType, null) == null) return false; // no IReadOnlyCollection<T> found

            // and we want to use the builder API, so for generic Foo<T> or IFoo<T> we want to use Foo.CreateBuilder<T>
            string name = declaredType.Name;
            int i = name.IndexOf('`');
            if (i <= 0) return false;
            name = declaredTypeInfo.IsInterface ? name.Substring(1, i - 1) : name.Substring(0, i);

            Type outerType = model.GetType(declaredType.Namespace + "." + name, declaredTypeInfo.Assembly);
            // I hate special-cases...
            if (outerType == null && name == "ImmutableSet")
            {
                outerType = model.GetType(declaredType.Namespace + ".ImmutableHashSet", declaredTypeInfo.Assembly);
            }
            if (outerType == null) return false;

#if WINRT
            foreach (MethodInfo method in outerType.GetTypeInfo().DeclaredMethods)
#else
            foreach (MethodInfo method in outerType.GetMethods())
#endif
            {
                if (!method.IsStatic || method.Name != "CreateBuilder" || !method.IsGenericMethodDefinition || method.GetParameters().Length != 0
                    || method.GetGenericArguments().Length != typeArgs.Length) continue;

                builderFactory = method.MakeGenericMethod(typeArgs);
                break;
            }
            Type voidType = model.MapType(typeof(void));
            if (builderFactory == null || builderFactory.ReturnType == null || builderFactory.ReturnType == voidType) return false;


            add = Helpers.GetInstanceMethod(builderFactory.ReturnType, "Add", effectiveType);
            if (add == null) return false;

            finish = Helpers.GetInstanceMethod(builderFactory.ReturnType, "ToImmutable", Helpers.EmptyTypes);
            if (finish == null || finish.ReturnType == null || finish.ReturnType == voidType) return false;

            if (!(finish.ReturnType == declaredType || Helpers.IsAssignableFrom(declaredType, finish.ReturnType))) return false;

            addRange = Helpers.GetInstanceMethod(builderFactory.ReturnType, "AddRange", new Type[] { declaredType });
            if (addRange == null)
            {
                Type enumerable = model.MapType(typeof(System.Collections.Generic.IEnumerable<>), false);
                if (enumerable != null)
                {
                    addRange = Helpers.GetInstanceMethod(builderFactory.ReturnType, "AddRange", new Type[] { enumerable.MakeGenericType(effectiveType) });
                }
            }

            return true;
        }
 internal static bool IdentifyImmutable(TypeModel model, Type declaredType, out MethodInfo builderFactory, out MethodInfo add, out MethodInfo addRange, out MethodInfo finish)
 {
     MethodInfo methodInfo;
     finish = (methodInfo = null);
     addRange = (methodInfo = methodInfo);
     add = (methodInfo = methodInfo);
     builderFactory = methodInfo;
     if (model == null || declaredType == null)
     {
         return false;
     }
     if (!declaredType.IsGenericType)
     {
         return false;
     }
     Type[] genericArguments = declaredType.GetGenericArguments();
     int num = genericArguments.Length;
     Type[] array;
     if (num != 1)
     {
         if (num != 2)
         {
             return false;
         }
         Type type = model.MapType(typeof(KeyValuePair<, >));
         if (type == null)
         {
             return false;
         }
         type = type.MakeGenericType(genericArguments);
         array = new Type[]
         {
             type
         };
     }
     else
     {
         array = genericArguments;
     }
     if (ImmutableCollectionDecorator.ResolveIReadOnlyCollection(declaredType, null) == null)
     {
         return false;
     }
     string text = declaredType.Name;
     int num2 = text.IndexOf('`');
     if (num2 <= 0)
     {
         return false;
     }
     text = ((!declaredType.IsInterface) ? text.Substring(0, num2) : text.Substring(1, num2 - 1));
     Type type2 = model.GetType(declaredType.Namespace + "." + text, declaredType.Assembly);
     if (type2 == null && text == "ImmutableSet")
     {
         type2 = model.GetType(declaredType.Namespace + ".ImmutableHashSet", declaredType.Assembly);
     }
     if (type2 == null)
     {
         return false;
     }
     MethodInfo[] methods = type2.GetMethods();
     for (int i = 0; i < methods.Length; i++)
     {
         MethodInfo methodInfo2 = methods[i];
         if (methodInfo2.IsStatic && !(methodInfo2.Name != "CreateBuilder") && methodInfo2.IsGenericMethodDefinition && methodInfo2.GetParameters().Length == 0 && methodInfo2.GetGenericArguments().Length == genericArguments.Length)
         {
             builderFactory = methodInfo2.MakeGenericMethod(genericArguments);
             break;
         }
     }
     Type type3 = model.MapType(typeof(void));
     if (builderFactory == null || builderFactory.ReturnType == null || builderFactory.ReturnType == type3)
     {
         return false;
     }
     add = Helpers.GetInstanceMethod(builderFactory.ReturnType, "Add", array);
     if (add == null)
     {
         return false;
     }
     finish = Helpers.GetInstanceMethod(builderFactory.ReturnType, "ToImmutable", Helpers.EmptyTypes);
     if (finish == null || finish.ReturnType == null || finish.ReturnType == type3)
     {
         return false;
     }
     if (finish.ReturnType != declaredType && !Helpers.IsAssignableFrom(declaredType, finish.ReturnType))
     {
         return false;
     }
     addRange = Helpers.GetInstanceMethod(builderFactory.ReturnType, "AddRange", new Type[]
     {
         declaredType
     });
     if (addRange == null)
     {
         Type type4 = model.MapType(typeof(IEnumerable<>), false);
         if (type4 != null)
         {
             addRange = Helpers.GetInstanceMethod(builderFactory.ReturnType, "AddRange", new Type[]
             {
                 type4.MakeGenericType(array)
             });
         }
     }
     return true;
 }