void Initialize() { if (_memberHandlers is null) { InitializeCore(); } void InitializeCore() { var pgType = (PostgresCompositeType)PostgresType; _memberHandlers = CreateMemberHandlers(pgType, _typeMapper, _nameTranslator); _constructorHandler = CreateConstructorHandler(pgType, _typeMapper, _nameTranslator); _constructor = _constructorHandler is null ? Expression .Lambda <Func <T> >(Expression.New(typeof(T))) .Compile() : null; } }
static CompositeConstructorHandler <T>?CreateConstructorHandler(PostgresCompositeType pgType, ConnectorTypeMapper typeMapper, INpgsqlNameTranslator nameTranslator) { var pgFields = pgType.Fields; var clrType = typeof(T); ConstructorInfo?clrDefaultConstructor = null; foreach (var clrConstructor in clrType.GetConstructors()) { var clrParameters = clrConstructor.GetParameters(); if (clrParameters.Length != pgFields.Count) { if (clrParameters.Length == 0) { clrDefaultConstructor = clrConstructor; } continue; } var clrParameterHandlerCount = 0; var clrParametersMapped = new ParameterInfo[pgFields.Count]; foreach (var clrParameter in clrParameters) { var attr = clrParameter.GetCustomAttribute <PgNameAttribute>(); var name = attr?.PgName ?? (clrParameter.Name is string clrName ? nameTranslator.TranslateMemberName(clrName) : null); if (name is null) { break; } for (var pgFieldIndex = pgFields.Count - 1; pgFieldIndex >= 0; --pgFieldIndex) { var pgField = pgFields[pgFieldIndex]; if (pgField.Name != name) { continue; } if (clrParametersMapped[pgFieldIndex] != null) { throw new AmbiguousMatchException($"Multiple constructor parameters are mapped to the '{pgField.Name}' field."); } clrParameterHandlerCount++; clrParametersMapped[pgFieldIndex] = clrParameter; break; } } if (clrParameterHandlerCount < pgFields.Count) { continue; } var clrParameterHandlers = new CompositeParameterHandler[pgFields.Count]; for (var pgFieldIndex = 0; pgFieldIndex < pgFields.Count; ++pgFieldIndex) { var pgField = pgFields[pgFieldIndex]; if (!typeMapper.TryGetByOID(pgField.Type.OID, out var handler)) { throw new NpgsqlException($"PostgreSQL composite type {pgType.DisplayName} has field {pgField.Type.DisplayName} with an unknown type (OID = {pgField.Type.OID})."); } var clrParameter = clrParametersMapped[pgFieldIndex]; var clrParameterHandlerType = typeof(CompositeParameterHandler <>) .MakeGenericType(clrParameter.ParameterType); clrParameterHandlers[pgFieldIndex] = (CompositeParameterHandler)Activator.CreateInstance( clrParameterHandlerType, BindingFlags.Instance | BindingFlags.Public, binder: null, args: new object[] { handler, clrParameter }, culture: null) !; } return(CompositeConstructorHandler <T> .Create(pgType, clrConstructor, clrParameterHandlers)); } if (clrDefaultConstructor is null && !clrType.IsValueType) { throw new InvalidOperationException($"No parameterless constructor defined for type '{clrType}'."); } return(null); }