private static ReadOnlyCollection <Type> GetConcreteTypesCore(Type genericType, LinkList <Binding> bindings) { Debug.Assert(genericType != null); Debug.Assert(bindings != null); bool cached = concreteTypeCache_.ContainsKey(genericType); bool unbound = genericType.GetGenericArguments( ) .All((a) => !Binding.ContainsArgument(bindings, a)); // If the type has already been evaluated and there are no interfering bindings, return cached value. if (cached && unbound) { return(concreteTypeCache_[genericType]); } // Otherwise, get a concrete type for each set of bindings. LinkList <Type> openArguments; BindingCollection concreteTypeBindngs = GenericTypeResolver.GetConcreteTypeBindings(genericType, bindings, out openArguments); var concreteTypes = concreteTypeBindngs .Transform((argumentBindings) => MakeConcreteType(genericType, openArguments, argumentBindings)) .ToReadOnlyCollection( ); // If there are no interfering bindings, cache the concrete types. if (!cached && unbound) { concreteTypeCache_.TryAdd(genericType, concreteTypes); concreteTypes = concreteTypeCache_[genericType]; } return(concreteTypes); }
public void GetConcreteMethods_succeeds_for_generic_method(string methodName, Type[] genericArguments) { var method = GetMethod(methodName); var concreteMethods = GenericTypeResolver.GetConcreteMethods(method) .ToArray( ); Assert.NotNull(concreteMethods); if (genericArguments == null) { Assert.Empty(concreteMethods); } else { Assert.NotEmpty(concreteMethods); Assert.Equal(1, concreteMethods.Length); var constructedMethod = method.MakeGenericMethod(genericArguments); Assert.Equal(constructedMethod, concreteMethods[0]); foreach (var parameter in constructedMethod.GetParameters( )) { var instances = TypeCreator.GetCreators(parameter.ParameterType); Assert.Equal(1, instances.Count); } } }
private static IEnumerable <IInstanceCreator> GetGenericCreators(Type targetType, Type genericType) { Debug.Assert(targetType != null); Debug.Assert(genericType != null); Debug.Assert(genericType.ContainsGenericParameters); // Get all bindings for the generic type's arguments that satisfy the inheritance constraint. var openArguments = GenericTypeResolver.GetOpenGenericArguments(genericType); Assembly[] referenceAssemblies; LinkList <Constraint> inheritanceConstraints = targetType.IsGenericParameter ? Constraint.GetConstraints(targetType, out referenceAssemblies) : Constraint.GetInheritanceConstraint(targetType).MakeLinkList( ); var argumentBindings = new BindingCollection(Binding.EmptyBindings); Constraint.SatisfyConstraints(argumentBindings, genericType, inheritanceConstraints); // Construct concrete types for each set of argument bindings, // and return the creators for each concrete type. var creators = from arguments in argumentBindings let concreteType = GenericTypeResolver.CreateConcreteType(genericType, openArguments, arguments) where concreteType != null from creator in TypeCreator.GetInstanceCreators(targetType, concreteType) select creator; return(creators); }
public void GetOpenGenericArguments_returns_expected_number_of_arguments_for_type(Type type, int expectedCount) { var arguments = GenericTypeResolver.GetOpenGenericArguments(type); Assert.NotNull(arguments); Assert.Equal(expectedCount, arguments.Count); }
public void GetConcreteMethods_succeeds_for_concrete_method( ) { var method = GetMethod("ConcreteMethod"); var concreteMethods = GenericTypeResolver.GetConcreteMethods(method); Assert.Equal(method, Assert.Single(concreteMethods)); }
public void GetConcreteTypes_returns_argument_for_concrete_type( ) { Type concreteType = typeof(int); var types = GenericTypeResolver.GetConcreteTypes(concreteType); Assert.Equal(concreteType, Assert.Single(types)); }
public void GetConcreteTypes_returns_no_types_for_unconstrained_generic_type( ) { Type genercType = typeof(UnconstrainedGenericType <>); var types = GenericTypeResolver.GetConcreteTypes(genercType); Assert.Empty(types); }
public void CreateConcreteType_returns_null_for_generic_type_with_partial_bindings( ) { Type type = typeof(IDictionary <,>); var openArguments = GenericTypeResolver.GetOpenGenericArguments(type); var bindings = Binding.EmptyBindings.Add(new Binding(openArguments.Value, typeof(int))); var concreteType = GenericTypeResolver.CreateConcreteType(type, openArguments, bindings); Assert.Null(concreteType); }
public void CreateConcreteType_returns_null_for_generic_type_with_no_bindings( ) { Type type = typeof(Nullable <>); var openArguments = GenericTypeResolver.GetOpenGenericArguments(type); var bindings = Binding.EmptyBindings; var concreteType = GenericTypeResolver.CreateConcreteType(type, openArguments, bindings); Assert.Null(concreteType); }
/// <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 CreateConcreteType_succeeds_for_concrete_type( ) { Type type = typeof(int); var openArguments = GenericTypeResolver.GetOpenGenericArguments(type); var bindings = Binding.EmptyBindings; var concreteType = GenericTypeResolver.CreateConcreteType(type, openArguments, bindings); Assert.NotNull(concreteType); Assert.Equal(type, concreteType); }
public void GetConcreteTypes_returns_one_type_for_bound_generic_type( ) { Type genercType = typeof(UnconstrainedGenericType <>); Type genercArgument = genercType.GetGenericArguments( )[0]; var genercArgumentBinding = new Binding(genercArgument, typeof(int)); var bindings = Binding.EmptyBindings.Add(genercArgumentBinding); var concreteType = genercType.MakeGenericType(genercArgumentBinding.Type); var types = GenericTypeResolver.GetConcreteTypes(genercType, bindings); Assert.Equal(concreteType, Assert.Single(types)); }
private static IEnumerable <IInstanceCreator> GetMethodCreators(Type targetType, MethodBase method) { Debug.Assert(targetType != null); Debug.Assert(method != null); Debug.Assert(method.IsGenericMethod || !targetType.ContainsGenericParameters); // Ignore recursive parameters. var parameters = method.GetParameters( ); if (parameters.Any(p => p.ParameterType.Is(targetType) || p.ParameterType.Is(method.DeclaringType))) { yield break; } // Retrieve creators for each parameter. var availableArguments = parameters.Select((p) => TypeCreator.GetInstanceCreators(p.ParameterType).AsEnumerable( )); // Call constructor with all argument permutations. foreach (var arguments in Permuter.Permute(availableArguments)) { // If method is concrete, use it. if (!method.IsGenericMethod) { yield return(WeakInstanceCreator.ForMethod(targetType, method, arguments)); } // Otherwise, try to resolve generic arguments on method. else if (method is MethodInfo) { var methodInfo = (MethodInfo)method; var bindings = new BindingCollection(Binding.EmptyBindings); for (int i = 0; i < parameters.Length; ++i) { ParameterInfo parameter = parameters[i]; IInstanceCreator argument = arguments[i]; if (parameter.ParameterType.ContainsGenericParameters) { GenericTypeResolver.GetAssignedGenericArguments(bindings, argument.InstanceType, parameter.ParameterType); } } foreach (LinkList <Binding> b in bindings) { var concreteMethod = GenericTypeResolver.MakeConcreteMethod(methodInfo, b); if (concreteMethod != null) { targetType = concreteMethod.ReturnType; yield return(WeakInstanceCreator.ForMethod(targetType, concreteMethod, arguments)); } } } } }
public void GetCreators_returns_expected_instances_for_generic_method_argument_types(MethodInfo genericMethod) { var concreteMethods = GenericTypeResolver.GetConcreteMethods(genericMethod); foreach (var method in concreteMethods) { Type genericType = method.GetParameters( ).Single( ).ParameterType; var creators = TypeCreator.GetCreators(genericType); TestCreators(genericType, new[] { genericType }, creators); } }
private static IEnumerable <IInstanceCreator> GetConstructorCreators(Type targetType, Type availableType) { Debug.Assert(targetType != null); Debug.Assert(availableType != null); Debug.Assert(!availableType.IsAbstract); if (targetType.ContainsGenericParameters) { Type definition = targetType.IsGenericParameter ? targetType : targetType.GetGenericTypeDefinition( ); var bindings = new BindingCollection(Binding.EmptyBindings); GenericTypeResolver.GetAssignedGenericArguments(bindings, availableType, definition); foreach (var binding in bindings) { Type resolvedType = definition.IsGenericParameter ? Binding.ForArgument(binding, definition).Type : GenericTypeResolver.MakeConcreteType(definition, binding); targetType = resolvedType; break; } } var creators = new List <IInstanceCreator>( ); // If type is an enumeration, get creator for enum values. if (availableType.IsEnum || availableType == typeof(bool)) { creators.AddRange(WeakInstanceCreator.ForEnum(availableType)); } // Otherwise, get creator for any default constructor. else if (Constraint.HasDefaultConstructor(availableType)) { creators.Add(WeakInstanceCreator.ForType(availableType)); } // Get creators for any parameterized constructors. var parameterizedConstructors = availableType.GetConstructors( ).Where((c) => c.GetParameters( ).Length > 0).ToArray( ); if (parameterizedConstructors.Length < 3) { foreach (var constructor in parameterizedConstructors) { creators.AddRange(TypeCreator.GetMethodCreators(targetType, constructor)); } } return(creators); }
public void GetConcreteMethods_succeeds_for_generic_class_method( ) { string methodName = "GenericMethod"; Type type = typeof(GenericMethodClass <>); var method = type.GetMethod(methodName); Assert.NotNull(method); var concreteMethods = GenericTypeResolver.GetConcreteMethods(method); var constructedType = type.MakeGenericType(typeof(SimpleParameter)); var constructedMethod = type.GetMethod(methodName); Assert.Equal(constructedMethod, Assert.Single(concreteMethods)); }
public void CreateConcreteType_succeeds_for_generic_type_with_duplicate_bindings( ) { Type genericType = typeof(Nullable <>); var openArguments = GenericTypeResolver.GetOpenGenericArguments(genericType); var bindings = GetBindingList(new[] { new Binding(openArguments.Value, typeof(int)), new Binding(openArguments.Value, typeof(int)) }); var concreteType = GenericTypeResolver.CreateConcreteType(genericType, openArguments, bindings); Assert.NotNull(concreteType); Assert.Equal(genericType, concreteType.GetGenericTypeDefinition( )); var constructedType = genericType.MakeGenericType(typeof(int)); Assert.Equal(constructedType, concreteType); }
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); }
public void GetConcreteMethods_succeeds_for_generic_method_with_multiple_resolutions( ) { const string methodName = "GenericMethod_MultipleFactoryResolutions"; var method = GetMethod(methodName); var concreteMethods = GenericTypeResolver.GetConcreteMethods(method) .ToArray( ); Assert.Equal(2, concreteMethods.Length); foreach (var concreteMethod in concreteMethods) { var parameter = concreteMethod.GetParameters( ).Single( ); var instances = TypeCreator.GetCreators(parameter.ParameterType); Assert.Equal(1, instances.Count); } }
public void GetConcreteMethods_succeeds_for_generic_method_with_multiple_generic_resolutions(MethodInfo method) { Type[] resolutionArguments = new[] { typeof(int), typeof(double) }; var concreteMethods = GenericTypeResolver.GetConcreteMethods(method) .ToArray( ); Assert.NotNull(concreteMethods); Assert.NotEmpty(concreteMethods); Assert.Equal(2, concreteMethods.Length); foreach (var m in concreteMethods) { Type[] genericArguments = m.GetGenericArguments( ); Assert.NotEmpty(genericArguments); Assert.Contains(genericArguments[0], resolutionArguments); } }
public void CreateConcreteType_succeeds_for_generic_type_with_full_bindings(Type genericType) { var openArguments = GenericTypeResolver.GetOpenGenericArguments(genericType); var bindings = GetBindingList(openArguments.Select((a, i) => new Binding(a, typeof(int)))); var concreteType = GenericTypeResolver.CreateConcreteType(genericType, openArguments, bindings); Assert.NotNull(concreteType); Assert.Equal(genericType, concreteType.GetGenericTypeDefinition( )); Type[] typeArguments = new Type[bindings.Count]; for (int i = 0; i < typeArguments.Length; ++i) { typeArguments[i] = typeof(int); } var constructedType = genericType.MakeGenericType(typeArguments); Assert.Equal(constructedType, concreteType); }
protected override IEnumerable <LinkList <Binding> > SatisfyCore(Type availableType, LinkList <Binding> bindings) { var newBindings = new List <LinkList <Binding> >( ); var currentBindngs = new BindingCollection(bindings); // Check if the available type derives from the base type. if (availableType.Is(this.requiredBaseType_)) { // Add any generic arguments assigned by the base type. if (this.requiredBaseType_.IsGenericType && !this.requiredBaseType_.ContainsGenericParameters) { IEnumerable <Type> correspondingTypes = GenericTypeResolver.GetCorrespondingBaseTypes(availableType, this.requiredBaseType_); foreach (Type correspondingType in correspondingTypes) { if (correspondingType.ContainsGenericParameters) { GenericTypeResolver.GetAssignedGenericArguments(currentBindngs, this.requiredBaseType_, correspondingType); } } } // Check all concrete version of the available type. foreach (LinkList <Binding> b in currentBindngs) { var concreteTypes = GenericTypeResolver.GetConcreteTypes(availableType, b); foreach (Type concreteAvailableType in concreteTypes) { // Add any newly assigned bindings from concrete and base types. var assignedBindings = new BindingCollection(b); GenericTypeResolver.GetAssignedGenericArguments(assignedBindings, concreteAvailableType, availableType); if (this.requiredBaseType_.ContainsGenericParameters) { GenericTypeResolver.GetAssignedGenericArguments(assignedBindings, concreteAvailableType, this.requiredBaseType_); } newBindings.AddRange(assignedBindings); } } } return(newBindings); }
private static MethodInfo MakeConcreteMethod(MethodInfo method, LinkList <Type> openArguments, LinkList <Binding> bindings) { Debug.Assert(method != null); Debug.Assert(openArguments != null); Debug.Assert(bindings != null); // If the method is not generic, return it immediately. if (!method.IsGenericMethodDefinition) { Debug.Assert(openArguments.IsEmpty); return(method); } // Otherwise, retrieve bindings for open arguments and construct the method. var boundArguments = GenericTypeResolver.BindConcreteArguments(openArguments, bindings); var concreteMethod = (boundArguments.Length == openArguments.Count ? method.MakeGenericMethod(boundArguments) : null); return(concreteMethod); }
private static Type MakeConcreteType(Type genericType, LinkList <Type> openArguments, LinkList <Binding> bindings) { Debug.Assert(genericType != null); Debug.Assert(openArguments != null); Debug.Assert(bindings != null); // If the type is concrete, return it immediately. if (!genericType.ContainsGenericParameters) { Debug.Assert(openArguments.IsEmpty); return(genericType); } // Otherwise, retrieve bindings for open arguments and construct the type. var boundArguments = GenericTypeResolver.BindConcreteArguments(openArguments, bindings); Debug.Assert(boundArguments.Length <= openArguments.Count); var concreteType = (boundArguments.Length == openArguments.Count ? genericType.MakeGenericType(boundArguments) : null); return(concreteType); }
public static IInstanceCreator ForInstanceCreator(Type targetType, IInstanceCreator creator) { Debug.Assert(creator != null); Debug.Assert(targetType != null); Debug.Assert(targetType.IsGenericType && targetType.GetGenericTypeDefinition( ) == typeof(IInstanceCreator <>)); IInstanceCreator finalCreator = creator; Type creatorType = creator.GetType( ); Type targetCreatedType = targetType.GetGenericArguments( )[0]; // Ensure target type is closed. Type finalTargetType = targetType; if (finalTargetType.ContainsGenericParameters) { targetCreatedType = GenericTypeResolver.GetCorrespondingBaseTypes(finalCreator.InstanceType, targetCreatedType).Single( ); finalTargetType = typeof(IInstanceCreator <>).MakeGenericType(targetCreatedType); } // If the creator does not have the same type as the target, wrap the creator to return instances of the target base type. if (!creatorType.Is(finalTargetType)) { Type actualCreatedType = creatorType.GetInterfaces( ) .Single(i => i.IsGenericType && i.GetGenericTypeDefinition( ) == typeof(IInstanceCreator <>)) .GetGenericArguments( )[0]; Type wrapperType = typeof(InstanceCreatorWrapper <,>).MakeGenericType(targetCreatedType, actualCreatedType); finalCreator = (IInstanceCreator)Activator.CreateInstance(wrapperType, creator); } // Get IInstanceCreator to return the given creator instance. Type funcType = typeof(Func <>).MakeGenericType(finalTargetType); var lambda = Expression.Lambda(funcType, Expression.Constant(finalCreator, finalTargetType)); var nestingCreator = WeakInstanceCreator.ForDelegate(lambda.Compile( )); return(nestingCreator); }
private static BindingCollection GetConcreteTypeBindings(Type type, LinkList <Binding> bindings, out LinkList <Type> openArguments) { Debug.Assert(type != null); Debug.Assert(bindings != null); // Avoid recursive searches for generic type. if (type.ContainsGenericParameters) { if (Binding.ContainsType(bindings, type)) { openArguments = LinkList <Type> .Empty; return(new BindingCollection( )); } bindings = bindings.Add(new Binding(null, type)); } // Bind all unassigned generic argument on the generic type. openArguments = GenericTypeResolver.GetOpenGenericArguments(type); var collection = new BindingCollection(bindings); GenericTypeResolver.BindGenericArguments(collection, openArguments); return(collection); }
public void GetConcreteTypes_returns_expected_types_for_generic_type(Type genericType, Type[] expectedConcreteTypes) { var concreteTypes = GenericTypeResolver.GetConcreteTypes(genericType); TestConcreteTypes(genericType, expectedConcreteTypes, concreteTypes); }
public static Type MakeConcreteType(Type genericType, LinkList <Binding> bindings) { var openArguments = GenericTypeResolver.GetOpenGenericArguments(genericType); return(GenericTypeResolver.MakeConcreteType(genericType, openArguments, bindings)); }
public static ICollection <MethodInfo> GetConcreteMethods(MethodInfo genericMethod) { return(GenericTypeResolver.GetConcreteMethods(genericMethod, Binding.EmptyBindings)); }
public static MethodInfo MakeConcreteMethod(MethodInfo method, LinkList <Binding> bindings) { var openArguments = GenericTypeResolver.GetOpenGenericArguments(method.GetGenericArguments( )); return(GenericTypeResolver.MakeConcreteMethod(method, openArguments, bindings)); }