private static IEnumerable <IInstanceCreator> GetFactoryCreators(Type targetType, Type availableType) { Debug.Assert(targetType != null); Debug.Assert(availableType != null); Debug.Assert(availableType.IsAbstract && availableType.IsSealed); var factoryMethods = from m in availableType.GetMethods(BindingFlags.Public | BindingFlags.Static) // Check that method is a "GetInstances" factory method, and returns an IEnumerable<> collection. where m.Name.StartsWith("Get", StringComparison.OrdinalIgnoreCase) && m.Name.EndsWith("Instances", StringComparison.OrdinalIgnoreCase) && m.ReturnType.IsGenericType && m.ReturnType.GetGenericTypeDefinition( ) == typeof(IEnumerable <>) // Check that the enumerable collection is of type Func<>. let enumerableArgType = m.ReturnType.GetGenericArguments( )[0] where enumerableArgType.IsGenericType && enumerableArgType.GetGenericTypeDefinition( ) == typeof(Func <>) // Check that the return type of the Func<> delegate is valid for the target type. let funcArgType = enumerableArgType.GetGenericArguments( )[0] where targetType.Is(funcArgType) select m; // Call each factory method, returning creators from the resulting Func<> delegates. var factoryCreators = from method in factoryMethods from methodCreator in TypeCreator.GetMethodCreators(method.ReturnType, method) let funcCollection = (System.Collections.IEnumerable)methodCreator.CreateInstance( ) from func in funcCollection.Cast <object>( ) let creator = WeakInstanceCreator.ForDelegate(func) select creator; return(factoryCreators); }
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)); } } } } }
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); }
private static ReadOnlyCollection <IInstanceCreator> GetInstanceCreators(Type targetType) { Debug.Assert(targetType != null); Debug.Assert(targetType.IsVisible); // If creators have not been cached, or are in the process of being cached, take lock and re-check cache. ReadOnlyCollection <IInstanceCreator> cached; if (!creatorCache_.TryGetValue(targetType, out cached) || object.ReferenceEquals(cached, TempCreators)) { bool isInstanceCreator = targetType.IsGenericType && targetType.GetGenericTypeDefinition( ) == typeof(IInstanceCreator <>); Type[] availableTypes = isInstanceCreator ? null : TypeLoader.GetUsableTypes(targetType).ToArray( ); lock ( creatorCacheLock_ ) { if (!TypeCreator.creatorCache_.ContainsKey(targetType)) { TypeCreator.creatorCache_[targetType] = TempCreators; ReadOnlyCollection <IInstanceCreator> creators; // If target type is for IInstanceCreator<T>, wrap creators for T. if (isInstanceCreator) { Type innerTargetType = targetType.GetGenericArguments( )[0]; var innerCreators = TypeCreator.GetCreators(innerTargetType); var outerCreators = new IInstanceCreator[innerCreators.Count]; for (int i = 0; i < outerCreators.Length; ++i) { outerCreators[i] = WeakInstanceCreator.ForInstanceCreator(targetType, innerCreators[i]); } creators = outerCreators.ToReadOnlyCollection( ); } // Otherwise, get creators for type directly. else { creators = GetInstanceCreators(targetType, availableTypes); } TypeCreator.creatorCache_[targetType] = creators; } } } return(TypeCreator.creatorCache_[targetType]); }
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); }