/// <summary>
 /// Appends metadata object represented by its factory to the composite metadata being composed.
 /// </summary>
 /// <typeparam name="TBuilder">Builder type.</typeparam>
 /// <typeparam name="TMetadata">Metadata object type to append.</typeparam>
 /// <param name="builder">Target builder.</param>
 /// <param name="factory">Metadata object factory.</param>
 /// <returns>Target builder.</returns>
 /// <exception cref="T:System.InvalidOperationException">
 /// Thrown if metadata with same type has already been appended.
 /// </exception>
 public static TBuilder AddMetadata <TMetadata, TBuilder>(this TBuilder builder, Func <ICompositeMetadata, TMetadata> factory)
     where TMetadata : IMetadata
     where TBuilder : ICompositeMetdataBuilder
 {
     builder.Add(typeof(TMetadata), MetadataDescriptor.Create(factory));
     return(builder);
 }
            public override Maybe <IMetadata> TryGetValueImpl(MetadataDescriptor descriptor)
            {
                var desc = (MetadataDescriptor <T>)descriptor;

                return(desc.Match(
                           onValue: v => ((IMetadata)v).AsMaybe(),
                           onFactory: _ => Maybe.Empty
                           ));
            }
            public override Maybe <IMetadata> TryInitializeImpl(MetadataDescriptor descriptor, IServiceProvider serviceProvider, ICompositeMetadata target)
            {
                var desc = (MetadataDescriptor <T>)descriptor;

                return(desc.Match(
                           onFactory: factory => ((IMetadata)factory(serviceProvider, target)).AsMaybe(),
                           onValue: _ => Maybe.Empty
                           ));
            }
 public abstract Maybe <IMetadata> TryInitializeImpl(MetadataDescriptor descriptor, IServiceProvider serviceProvider, ICompositeMetadata target);
 public abstract Maybe <IMetadata> TryGetValueImpl(MetadataDescriptor descriptor);
 public static Maybe <IMetadata> TryInitialize(MetadataDescriptor descriptor, IServiceProvider serviceProvider, ICompositeMetadata target)
 => _cache.GetOrAdd(descriptor.MetadataType, mtype => (BoxedMatcher)Activator.CreateInstance(typeof(Impl <>).MakeGenericType(mtype), true))
 .TryInitializeImpl(descriptor, serviceProvider, target);
 public static Maybe <IMetadata> TryGetValue(MetadataDescriptor descriptor)
 => _cache.GetOrAdd(descriptor.MetadataType, mtype => (BoxedMatcher)Activator.CreateInstance(typeof(Impl <>).MakeGenericType(mtype), true))
 .TryGetValueImpl(descriptor);
 /// <summary>
 /// Appends metadata object represented by its factory to the composite metadata being composed overriding any
 /// previous assignment of metadata of the specified type.
 /// </summary>
 /// <typeparam name="TBuilder">Builder type.</typeparam>
 /// <typeparam name="TMetadata">Metadata object type to append or update.</typeparam>
 /// <param name="builder">Target builder.</param>
 /// <param name="factory">Metadata object factory.</param>
 /// <returns>Target builder.</returns>
 public static TBuilder SetMetadata <TMetadata, TBuilder>(this TBuilder builder, Func <ICompositeMetadata, TMetadata> factory)
     where TMetadata : IMetadata
     where TBuilder : ICompositeMetdataBuilder
 => builder.AddOrUpdateMetadata(factory, (_, f) => MetadataDescriptor.Create(f));
 /// <summary>
 /// Appends metadata object to the composite metadata being composed overriding any previous assignment of
 /// metadata of the specified type.
 /// </summary>
 /// <typeparam name="TBuilder">Builder type.</typeparam>
 /// <typeparam name="TMetadata">Metadata object type to append or update.</typeparam>
 /// <param name="builder">Target builder.</param>
 /// <param name="metadata">Metadata object instance.</param>
 /// <returns>Target builder.</returns>
 public static TBuilder SetMetadata <TMetadata, TBuilder>(this TBuilder builder, TMetadata metadata)
     where TMetadata : IMetadata
     where TBuilder : ICompositeMetdataBuilder
 => builder.AddOrUpdateMetadata(metadata, (_, md) => MetadataDescriptor.Create(md));
 /// <summary>
 /// Either appends metadata object represented by its factory to the composite metadata being composed, or
 /// updates existing metadata descriptor.
 /// </summary>
 /// <typeparam name="TBuilder">Builder type.</typeparam>
 /// <typeparam name="TMetadata">Metadata object type to append or update.</typeparam>
 /// <param name="builder">Target builder.</param>
 /// <param name="factory">Metadata object factory.</param>
 /// <param name="update">
 /// Function that is invoked if metadata descriptor has already been appended for the specified metadata type.
 /// </param>
 /// <returns>Target builder.</returns>
 public static TBuilder AddOrUpdateMetadata <TMetadata, TBuilder>(this TBuilder builder, Func <IServiceProvider, TMetadata> factory, Func <MetadataDescriptor, Func <IServiceProvider, TMetadata>, MetadataDescriptor> update)
     where TMetadata : IMetadata
     where TBuilder : ICompositeMetdataBuilder
 {
     builder[typeof(TMetadata)] = builder.TryGetValue(typeof(TMetadata), out var desc) ? update(desc, factory) : MetadataDescriptor.Create(factory);
     return(builder);
 }