/// <summary>
        /// Returns bindings for all assigned generic arguments in the specified list of bindings.
        /// </summary>
        public static void GetAssignedGenericArguments(BindingCollection bindings, Type concreteType, Type genericType)
        {
            Debug.Assert(bindings != null);
            Debug.Assert(concreteType != null);
            Debug.Assert(genericType != null);
            Debug.Assert(concreteType.Is(genericType));

            IEnumerable <Tuple <Type, Type> > concreteTypes = GetConcreteTypes(concreteType, genericType);

            bindings.Expand(concreteTypes, (currentBindings, tuple) => {
                Type type                  = tuple.Item1;
                Type generic               = tuple.Item2;
                Type[] assignedArguments   = type.GetGenericArguments( );
                Type[] unassignedArguments = generic.GetGenericArguments( );
                Debug.Assert(assignedArguments.Length == unassignedArguments.Length);

                for (int i = 0; currentBindings.Count > 0 && i < unassignedArguments.Length; ++i)
                {
                    Type unassignedArgument = unassignedArguments[i];
                    Type assignedArgument   = assignedArguments[i];

                    if (assignedArgument.IsGenericParameter)
                    {
                        continue;
                    }

                    if (!unassignedArgument.IsGenericParameter)
                    {
                        if (unassignedArgument.ContainsGenericParameters)
                        {
                            GenericTypeResolver.GetAssignedGenericArguments(currentBindings, assignedArgument, unassignedArgument);
                        }
                        continue;
                    }

                    if (!assignedArgument.Is(unassignedArgument))
                    {
                        currentBindings.Clear( );
                        break;
                    }

                    currentBindings.Reduce(b => {
                        Binding existingBinding = Binding.ForArgument(b, unassignedArgument);
                        return(existingBinding == null
                             ? b.Add(new Binding(unassignedArgument, assignedArgument))
                             : (existingBinding.Type == assignedArgument ? b : null));
                    });
                }

                if (genericType.IsGenericParameter)
                {
                    currentBindings.Reduce(b => b.Add(new Binding(genericType, concreteType)));
                }
            });
        }
Beispiel #2
0
        public void Expand_GivenCollectionProcessor_UpdatesWithAllBindings( )
        {
            var initial    = List(typeof(int));
            var expected   = new[] { List(typeof(Tuple <int>)), List(typeof(Tuple <int>)) };
            var collection = new BindingCollection(initial);

            collection.Expand(Enumerable.Repeat(1, 2), (bs, i) => bs.Reduce(b => List(typeof(Tuple <>).MakeGenericType(b.Value.Type))));
            var actual = collection.ToArray( );

            Assert.Equal(actual, expected);
        }
        private static ICollection <MethodInfo> GetConcreteMethods(MethodInfo method, LinkList <Binding> bindings)
        {
            Debug.Assert(method != null);
            Debug.Assert(bindings != null);


            // Try to resolve generic arguments on method.
            var openArguments    = GenericTypeResolver.GetOpenGenericArguments(method.GetGenericArguments( ));
            var concreteBindings = new BindingCollection(bindings);

            GenericTypeResolver.BindGenericArguments(concreteBindings, openArguments);

            var concreteMethods = concreteBindings.Transform((b) => MakeConcreteMethod(method, openArguments, b));


            // If generic arguments cannot be resolved statically, try to bind method arguments by searching for creatable parameter types.
            if (concreteMethods.Count == 0)
            {
                var genericParameterTypes = method.GetParameters( )
                                            .Select(p => p.ParameterType)
                                            .Where(t => t.IsGenericType)
                                            .ToArray( );
                Debug.Assert(genericParameterTypes.All(t => !t.IsGenericParameter));

                var creatableParameterTypes = genericParameterTypes
                                              .Select(t => TypeCreator.GetCreators(t)
                                                      .Select(c => c.InstanceType)
                                                      .Distinct( )
                                                      );

                var parameterBindings = new BindingCollection(bindings);
                parameterBindings.Expand(Permuter.Permute(creatableParameterTypes), (b, permutation) => {
                    for (int i = 0; i < permutation.Length; ++i)
                    {
                        Type permutationType      = permutation[i];
                        Type genericParameterType = genericParameterTypes[i];
                        GenericTypeResolver.GetAssignedGenericArguments(b, permutationType, genericParameterType);
                    }
                });

                concreteMethods = parameterBindings.Transform((b) => MakeConcreteMethod(method, openArguments, b));
            }


            return(concreteMethods);
        }
        private static void BindGenericArguments(BindingCollection bindings, LinkList <Type> openArguments)
        {
            Debug.Assert(bindings != null);
            Debug.Assert(openArguments != null);

            foreach (Type argument in openArguments)
            {
                // Get all types satisfying the current constraint.
                Assembly[] referenceAssemblies;
                var        constraints = Constraint.GetConstraints(argument, out referenceAssemblies);

                // If the argument has no limiting constraints, skip it.
                if (constraints.IsEmpty || referenceAssemblies.Length == 0)
                {
                    continue;
                }


                // Add each type satisfying the current generic argument to the list of bindings.
                bool onlyUsageConstraints = constraints.All((c) => c.IsUsageConstraint);
                bindings.Expand(TypeLoader.GetUsableTypes(referenceAssemblies), (constraintBindings, type) => {
                    LinkList <Type> openTypeArguments = GetOpenGenericArguments(type);
                    Constraint.SatisfyConstraints(constraintBindings, type, constraints);
                    constraintBindings.Reduce(constraintBinding => {
                        Type concreteType = MakeConcreteType(type, openTypeArguments, constraintBinding);
                        if (concreteType == null)
                        {
                            return(null);
                        }
                        else if (onlyUsageConstraints || Binding.ContainsArgument(constraintBinding, argument))
                        {
                            return(constraintBinding);
                        }
                        else
                        {
                            return(constraintBinding.Add(new Binding(argument, concreteType)));
                        }
                    });
                });

                if (bindings.Count == 0)
                {
                    break;
                }
            }
        }