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; }