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