private static ServiceDescriptor GetMetadataServiceDescriptor <T>(Type ImplementationType)
 {
     return(ServiceDescriptor.Transient(typeof(Lazy <T, ServiceTypeMetadata>),
                                        provider =>
                                        new Lazy <T, ServiceTypeMetadata>(
                                            () =>
                                            (T)provider.GetRequiredService(ImplementationType),
                                            ServiceTypeMetadataExtensions.GetServiceTypeMetadata(ImplementationType)
                                            )));
 }
        public static IServiceCollection AddMetadataDependency(this IServiceCollection services, Func <AssemblyName, bool> predicate = null)
        {
            var assemblies = GetAssemblies(predicate);

            var types = assemblies.SelectMany(i => i.GetExportedTypes())
                        .Where(t => t.GetTypeInfo()
                               .IsDefined(typeof(ServiceDescriptorAttribute), inherit: true)
                               );

            foreach (var type in types)
            {
                var typeInfo = type.GetTypeInfo();

                var attributes = typeInfo.GetCustomAttributes <ServiceDescriptorAttribute>().ToArray();

                // Check if the type has multiple attributes with same ServiceType.
                var duplicates = attributes
                                 .GroupBy(s => s.ServiceType)
                                 .SelectMany(grp => grp.Skip(1));

                if (duplicates.Any())
                {
                    throw new InvalidOperationException($@"Type ""{type.FullName}"" has multiple ServiceDescriptor attributes with the same service type.");
                }

                foreach (var attribute in attributes)
                {
                    var serviceTypes = getRequireMetadataServiceTypes(type, attribute);

                    foreach (var serviceType in serviceTypes)
                    {
                        //
                        var descriptor = new ServiceDescriptor(serviceType, type, attribute.Lifetime);

                        services.Add(descriptor);

                        if (serviceType.IsInterface)
                        {
                            var extensionDescriptor = (ServiceDescriptor)getMetadataServiceDescriptorMethodInfo
                                                      .MakeGenericMethod(descriptor.ServiceType)
                                                      .Invoke(null, new object[] { descriptor.ImplementationType });

                            services.Add(extensionDescriptor);

                            ServiceTypeMetadataExtensions.AddMetadata(descriptor.ImplementationType, attribute.Name);
                        }
                    }
                }
            }

            return(services);
        }