private ArgumentMapping[] GetTypeConstraintArgumentMappingsRecursive(ArgumentMapping mapping, IList <Type> processedTypes) { IEnumerable <Type> constraints = Enumerable.Empty <Type>(); if (mapping.Argument.IsGenericParameter) { //// If the type itself is a generic parameter such as TKey (and not for instance IBar<TValue>) //// We must skip it, since there is no mappings we can extract from it (while IBar<TValue> could). constraints = from constraint in mapping.Argument.GetGenericParameterConstraints() where !constraint.IsGenericParameter select constraint; } else { // In case we're dealing with partial generic type's (such as Lazy<List<T>>) the argument is // not a generic parameter and the argument (List<T> for instance) itself becomes the // constraints. } return(( from constraint in constraints let constraintMapping = new ArgumentMapping(constraint, mapping.ConcreteType) from arg in this.ConvertToOpenImplementationArgumentMappings(constraintMapping, processedTypes).ToArray() select arg) .ToArray()); }
private IEnumerable <ArgumentMapping> ConvertToOpenImplementationArgumentMappings( ArgumentMapping mapping, IList <Type> processedTypes) { // We are only interested in generic parameters if (mapping.Argument.IsGenericArgument() && !processedTypes.Contains(mapping.Argument)) { processedTypes.Add(mapping.Argument); if (this.implementationTypeDefinitionArguments.Contains(mapping.Argument)) { // The argument is one of the type's generic arguments. We can directly return it. yield return(mapping); foreach (var arg in this.GetTypeConstraintArgumentMappingsRecursive(mapping, processedTypes)) { yield return(arg); } } else { // The argument is not in the type's list, which means that the real type is (or are) // buried in a generic type (i.e. Nullable<KeyValueType<TKey, TValue>>). This can result // in multiple values. foreach (var arg in this.ConvertToOpenImplementationArgumentMappingsRecursive(mapping, processedTypes)) { yield return(arg); } } } }
private ArgumentMapping[] ConvertToOpenImplementationArgumentMappingsForType( ArgumentMapping mapping, Type type, IList <Type> processedTypes) { var arguments = mapping.Argument.GetGenericArguments(); var concreteTypes = type.GetGenericArguments(); if (concreteTypes.Length != arguments.Length) { // The length of the concrete list and the generic argument list does not match. This normally // means that the generic argument contains a argument that is not generic (so Int32 instead // of T). In that case we can ignore everything, because the type will be unusable. return(new ArgumentMapping[0]); } return(( from subMapping in ArgumentMapping.Zip(arguments, concreteTypes) from arg in this.ConvertToOpenImplementationArgumentMappings(subMapping, processedTypes).ToArray() select arg) .ToArray()); }
private ArgumentMapping[] ConvertToOpenImplementationArgumentMappingsRecursive( ArgumentMapping mapping, IList <Type> processedTypes) { // If we're dealing with a generic type argument here (which means we're in the verification // phase testing open generic types), we must just return the mapping, because we can't deduce // things any further. if (mapping.ConcreteType.IsGenericParameter) { return(new ArgumentMapping[] { mapping }); } var argumentTypeDefinition = mapping.Argument.GetGenericTypeDefinition(); // Try to get mappings for each type in the type hierarchy that is compatible to the argument. return(( from type in mapping.ConcreteType.GetTypeBaseTypesAndInterfacesFor(argumentTypeDefinition) from arg in this.ConvertToOpenImplementationArgumentMappingsForType(mapping, type, processedTypes) select arg) .ToArray()); }