/// <summary> /// Creates a converter that can convert a generic type instance that has the given types /// </summary> /// <param name="registryBuilder"></param> /// <param name="types"></param> /// <returns></returns> internal ITypeConverter CreateConverter(TypeRegistryBuilder registryBuilder, params Type[] types) { if (registryBuilder == null) { throw new ArgumentNullException(nameof(registryBuilder)); } if (types == null) { throw new ArgumentNullException(nameof(types)); } if (ConverterType.GenericTypeParameters.Length != types.Length) { throw new ArgumentException( $"Generic type {ConverterType.FullName} instantiation requested {types.Length} type arguments, {ConverterType.GenericTypeParameters.Length} required", nameof(types)); } var uniqueTypes = types.Distinct().ToArray(); //Look up the type meta data for each type so we can get the converter for each type var typesMetaData = new TypeMetaData[uniqueTypes.Length]; for (var i = 0; i < uniqueTypes.Length; ++i) { var type = uniqueTypes[i]; var metaData = registryBuilder.FindMetaDataByType(type); if (metaData == null) { throw new InvalidOperationException($"Generic type {ConverterType.FullName} instantion is referencing type {type.FullName}, which has not been registered"); } if (metaData.Converter == null) { throw new InvalidOperationException($"Generic type {ConverterType.FullName} instantion is referencing type {type.FullName}, which has no converter associated with it"); } typesMetaData[i] = metaData; } var instanceType = ConverterType.MakeGenericType(types); //Find a constructor that takes the unique arguments in the order that they first occurred var converterTypes = typesMetaData.Select(subConverter => subConverter.Converter.GetType()).ToArray(); var constructor = instanceType.GetConstructor(converterTypes); if (constructor == null) { throw new InvalidOperationException($"Generic type converter {ConverterType.FullName} does not have a constructor taking each generic type converter"); } var subConverters = typesMetaData.Select(subConverter => subConverter.Converter).ToArray(); return((ITypeConverter)constructor.Invoke(subConverters)); }
internal TypeMetaDataBuilder(TypeRegistryBuilder registryBuilder, Type type) { _registryBuilder = registryBuilder ?? throw new ArgumentNullException(nameof(registryBuilder)); Type = type ?? throw new ArgumentNullException(nameof(type)); if (type.IsGenericType && !type.IsConstructedGenericType) { throw new ArgumentException($"Type {type.FullName} is a generic type"); } if (_registryBuilder.FindMetaDataByType(type) != null) { throw new ArgumentException($"Type {type.FullName} has already been registered"); } }