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 CompositeMemberHandler <T>[] CreateMemberHandlers(PostgresCompositeType pgType, ConnectorTypeMapper typeMapper, INpgsqlNameTranslator nameTranslator) { var pgFields = pgType.Fields; var clrType = typeof(T); var clrMemberHandlers = new CompositeMemberHandler <T> [pgFields.Count]; var clrMemberHandlerCount = 0; var clrMemberHandlerType = IsValueType <T> .Value ? typeof(CompositeStructMemberHandler <,>) : typeof(CompositeClassMemberHandler <,>); foreach (var clrProperty in clrType.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { CreateMemberHandler(clrProperty, clrProperty.PropertyType); } foreach (var clrField in clrType.GetFields(BindingFlags.Instance | BindingFlags.Public)) { CreateMemberHandler(clrField, clrField.FieldType); } if (clrMemberHandlerCount != pgFields.Count) { var notMappedFields = string.Join(", ", clrMemberHandlers .Select((member, memberIndex) => member == null ? $"'{pgFields[memberIndex].Name}'" : null) .Where(member => member != null)); throw new InvalidOperationException($"PostgreSQL composite type {pgType.DisplayName} contains fields {notMappedFields} which could not match any on CLR type {clrType.Name}"); } return(clrMemberHandlers); void CreateMemberHandler(MemberInfo clrMember, Type clrMemberType) { var attr = clrMember.GetCustomAttribute <PgNameAttribute>(); var name = attr?.PgName ?? nameTranslator.TranslateMemberName(clrMember.Name); for (var pgFieldIndex = pgFields.Count - 1; pgFieldIndex >= 0; --pgFieldIndex) { var pgField = pgFields[pgFieldIndex]; if (pgField.Name != name) { continue; } if (clrMemberHandlers[pgFieldIndex] != null) { throw new AmbiguousMatchException($"Multiple class members are mapped to the '{pgField.Name}' field."); } 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})."); } clrMemberHandlerCount++; clrMemberHandlers[pgFieldIndex] = (CompositeMemberHandler <T>)Activator.CreateInstance( clrMemberHandlerType.MakeGenericType(clrType, clrMemberType), BindingFlags.Instance | BindingFlags.Public, binder: null, args: new object[] { clrMember, pgField.Type, handler }, culture: null) !; break; } } }