zoukankan      html  css  js  c++  java
  • netcore3.0 IServiceCollection 依赖注入系统(一)

    nuget包:在以Microsoft.Extensins.DependencyInjection开头的包中,直接引入对应的nuget包。

    github地址:https://github.com/dotnet/extensions/tree/master/src/DependencyInjection

    先看下这几个接口

     ServiceDescriptor类:

    该类是服务和其实现的描述,是整个依赖注入的基石

    [DebuggerDisplay("Lifetime = {Lifetime}, ServiceType = {ServiceType}, ImplementationType = {ImplementationType}")]
        public class ServiceDescriptor
        {
            /// <summary>
            /// Initializes a new instance of <see cref="ServiceDescriptor"/> with the specified <paramref name="implementationType"/>.
            /// </summary>
            /// <param name="serviceType">The <see cref="Type"/> of the service.</param>
            /// <param name="implementationType">The <see cref="Type"/> implementing the service.</param>
            /// <param name="lifetime">The <see cref="ServiceLifetime"/> of the service.</param>
            public ServiceDescriptor(
                Type serviceType,
                Type implementationType,
                ServiceLifetime lifetime)
                : this(serviceType, lifetime)
            {
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                if (implementationType == null)
                {
                    throw new ArgumentNullException(nameof(implementationType));
                }
    
                ImplementationType = implementationType;
            }
    
            /// <summary>
            /// Initializes a new instance of <see cref="ServiceDescriptor"/> with the specified <paramref name="instance"/>
            /// as a <see cref="ServiceLifetime.Singleton"/>.
            /// </summary>
            /// <param name="serviceType">The <see cref="Type"/> of the service.</param>
            /// <param name="instance">The instance implementing the service.</param>
            public ServiceDescriptor(Type serviceType, object instance)
                : this(serviceType, ServiceLifetime.Singleton)
            {
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                if (instance == null)
                {
                    throw new ArgumentNullException(nameof(instance));
                }
    
                ImplementationInstance = instance;
            }
    
            /// <summary>
            /// Initializes a new instance of <see cref="ServiceDescriptor"/> with the specified <paramref name="factory"/>.
            /// </summary>
            /// <param name="serviceType">The <see cref="Type"/> of the service.</param>
            /// <param name="factory">A factory used for creating service instances.</param>
            /// <param name="lifetime">The <see cref="ServiceLifetime"/> of the service.</param>
            public ServiceDescriptor(Type serviceType, Func<IServiceProvider, object> factory, ServiceLifetime lifetime)
                : this(serviceType, lifetime)
            {
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                if (factory == null)
                {
                    throw new ArgumentNullException(nameof(factory));
                }
    
                ImplementationFactory = factory;
            }
    
            private ServiceDescriptor(Type serviceType, ServiceLifetime lifetime)
            {
                Lifetime = lifetime;
                ServiceType = serviceType;
            }
    
            /// <inheritdoc />
            public ServiceLifetime Lifetime { get; }
    
            /// <inheritdoc />
            public Type ServiceType { get; }
    
            /// <inheritdoc />
            public Type ImplementationType { get; }
    
            /// <inheritdoc />
            public object ImplementationInstance { get; }
    
            /// <inheritdoc />
            public Func<IServiceProvider, object> ImplementationFactory { get; }
    
            /// <inheritdoc />
            public override string ToString()
            {
                var lifetime = $"{nameof(ServiceType)}: {ServiceType} {nameof(Lifetime)}: {Lifetime} ";
    
                if (ImplementationType != null)
                {
                    return lifetime + $"{nameof(ImplementationType)}: {ImplementationType}";
                }
    
                if (ImplementationFactory != null)
                {
                    return lifetime + $"{nameof(ImplementationFactory)}: {ImplementationFactory.Method}";
                }
    
                return lifetime + $"{nameof(ImplementationInstance)}: {ImplementationInstance}";
            }
    
            internal Type GetImplementationType()
            {
                if (ImplementationType != null)
                {
                    return ImplementationType;
                }
                else if (ImplementationInstance != null)
                {
                    return ImplementationInstance.GetType();
                }
                else if (ImplementationFactory != null)
                {
                    var typeArguments = ImplementationFactory.GetType().GenericTypeArguments;
    
                    Debug.Assert(typeArguments.Length == 2);
    
                    return typeArguments[1];
                }
    
                Debug.Assert(false, "ImplementationType, ImplementationInstance or ImplementationFactory must be non null");
                return null;
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <typeparamref name="TService"/>, <typeparamref name="TImplementation"/>,
            /// and the <see cref="ServiceLifetime.Transient"/> lifetime.
            /// </summary>
            /// <typeparam name="TService">The type of the service.</typeparam>
            /// <typeparam name="TImplementation">The type of the implementation.</typeparam>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Transient<TService, TImplementation>()
                where TService : class
                where TImplementation : class, TService
            {
                return Describe<TService, TImplementation>(ServiceLifetime.Transient);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <paramref name="service"/> and <paramref name="implementationType"/>
            /// and the <see cref="ServiceLifetime.Transient"/> lifetime.
            /// </summary>
            /// <param name="service">The type of the service.</param>
            /// <param name="implementationType">The type of the implementation.</param>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Transient(Type service, Type implementationType)
            {
                if (service == null)
                {
                    throw new ArgumentNullException(nameof(service));
                }
    
                if (implementationType == null)
                {
                    throw new ArgumentNullException(nameof(implementationType));
                }
    
                return Describe(service, implementationType, ServiceLifetime.Transient);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <typeparamref name="TService"/>, <typeparamref name="TImplementation"/>,
            /// <paramref name="implementationFactory"/>,
            /// and the <see cref="ServiceLifetime.Transient"/> lifetime.
            /// </summary>
            /// <typeparam name="TService">The type of the service.</typeparam>
            /// <typeparam name="TImplementation">The type of the implementation.</typeparam>
            /// <param name="implementationFactory">A factory to create new instances of the service implementation.</param>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Transient<TService, TImplementation>(
                Func<IServiceProvider, TImplementation> implementationFactory)
                where TService : class
                where TImplementation : class, TService
            {
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return Describe(typeof(TService), implementationFactory, ServiceLifetime.Transient);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <typeparamref name="TService"/>, <paramref name="implementationFactory"/>,
            /// and the <see cref="ServiceLifetime.Transient"/> lifetime.
            /// </summary>
            /// <typeparam name="TService">The type of the service.</typeparam>
            /// <param name="implementationFactory">A factory to create new instances of the service implementation.</param>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Transient<TService>(Func<IServiceProvider, TService> implementationFactory)
                where TService : class
            {
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return Describe(typeof(TService), implementationFactory, ServiceLifetime.Transient);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <paramref name="service"/>, <paramref name="implementationFactory"/>,
            /// and the <see cref="ServiceLifetime.Transient"/> lifetime.
            /// </summary>
            /// <param name="service">The type of the service.</param>
            /// <param name="implementationFactory">A factory to create new instances of the service implementation.</param>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Transient(Type service, Func<IServiceProvider, object> implementationFactory)
            {
                if (service == null)
                {
                    throw new ArgumentNullException(nameof(service));
                }
    
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return Describe(service, implementationFactory, ServiceLifetime.Transient);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <typeparamref name="TService"/>, <typeparamref name="TImplementation"/>,
            /// and the <see cref="ServiceLifetime.Scoped"/> lifetime.
            /// </summary>
            /// <typeparam name="TService">The type of the service.</typeparam>
            /// <typeparam name="TImplementation">The type of the implementation.</typeparam>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Scoped<TService, TImplementation>()
                where TService : class
                where TImplementation : class, TService
            {
                return Describe<TService, TImplementation>(ServiceLifetime.Scoped);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <paramref name="service"/> and <paramref name="implementationType"/>
            /// and the <see cref="ServiceLifetime.Scoped"/> lifetime.
            /// </summary>
            /// <param name="service">The type of the service.</param>
            /// <param name="implementationType">The type of the implementation.</param>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Scoped(Type service, Type implementationType)
            {
                return Describe(service, implementationType, ServiceLifetime.Scoped);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <typeparamref name="TService"/>, <typeparamref name="TImplementation"/>,
            /// <paramref name="implementationFactory"/>,
            /// and the <see cref="ServiceLifetime.Scoped"/> lifetime.
            /// </summary>
            /// <typeparam name="TService">The type of the service.</typeparam>
            /// <typeparam name="TImplementation">The type of the implementation.</typeparam>
            /// <param name="implementationFactory">A factory to create new instances of the service implementation.</param>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Scoped<TService, TImplementation>(
                Func<IServiceProvider, TImplementation> implementationFactory)
                where TService : class
                where TImplementation : class, TService
            {
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return Describe(typeof(TService), implementationFactory, ServiceLifetime.Scoped);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <typeparamref name="TService"/>, <paramref name="implementationFactory"/>,
            /// and the <see cref="ServiceLifetime.Scoped"/> lifetime.
            /// </summary>
            /// <typeparam name="TService">The type of the service.</typeparam>
            /// <param name="implementationFactory">A factory to create new instances of the service implementation.</param>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Scoped<TService>(Func<IServiceProvider, TService> implementationFactory)
                where TService : class
            {
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return Describe(typeof(TService), implementationFactory, ServiceLifetime.Scoped);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <paramref name="service"/>, <paramref name="implementationFactory"/>,
            /// and the <see cref="ServiceLifetime.Scoped"/> lifetime.
            /// </summary>
            /// <param name="service">The type of the service.</param>
            /// <param name="implementationFactory">A factory to create new instances of the service implementation.</param>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Scoped(Type service, Func<IServiceProvider, object> implementationFactory)
            {
                if (service == null)
                {
                    throw new ArgumentNullException(nameof(service));
                }
    
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return Describe(service, implementationFactory, ServiceLifetime.Scoped);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <typeparamref name="TService"/>, <typeparamref name="TImplementation"/>,
            /// and the <see cref="ServiceLifetime.Singleton"/> lifetime.
            /// </summary>
            /// <typeparam name="TService">The type of the service.</typeparam>
            /// <typeparam name="TImplementation">The type of the implementation.</typeparam>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Singleton<TService, TImplementation>()
                where TService : class
                where TImplementation : class, TService
            {
                return Describe<TService, TImplementation>(ServiceLifetime.Singleton);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <paramref name="service"/> and <paramref name="implementationType"/>
            /// and the <see cref="ServiceLifetime.Singleton"/> lifetime.
            /// </summary>
            /// <param name="service">The type of the service.</param>
            /// <param name="implementationType">The type of the implementation.</param>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Singleton(Type service, Type implementationType)
            {
                if (service == null)
                {
                    throw new ArgumentNullException(nameof(service));
                }
    
                if (implementationType == null)
                {
                    throw new ArgumentNullException(nameof(implementationType));
                }
    
                return Describe(service, implementationType, ServiceLifetime.Singleton);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <typeparamref name="TService"/>, <typeparamref name="TImplementation"/>,
            /// <paramref name="implementationFactory"/>,
            /// and the <see cref="ServiceLifetime.Singleton"/> lifetime.
            /// </summary>
            /// <typeparam name="TService">The type of the service.</typeparam>
            /// <typeparam name="TImplementation">The type of the implementation.</typeparam>
            /// <param name="implementationFactory">A factory to create new instances of the service implementation.</param>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Singleton<TService, TImplementation>(
                Func<IServiceProvider, TImplementation> implementationFactory)
                where TService : class
                where TImplementation : class, TService
            {
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return Describe(typeof(TService), implementationFactory, ServiceLifetime.Singleton);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <typeparamref name="TService"/>, <paramref name="implementationFactory"/>,
            /// and the <see cref="ServiceLifetime.Singleton"/> lifetime.
            /// </summary>
            /// <typeparam name="TService">The type of the service.</typeparam>
            /// <param name="implementationFactory">A factory to create new instances of the service implementation.</param>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Singleton<TService>(Func<IServiceProvider, TService> implementationFactory)
                where TService : class
            {
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return Describe(typeof(TService), implementationFactory, ServiceLifetime.Singleton);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <paramref name="serviceType"/>, <paramref name="implementationFactory"/>,
            /// and the <see cref="ServiceLifetime.Singleton"/> lifetime.
            /// </summary>
            /// <param name="serviceType">The type of the service.</param>
            /// <param name="implementationFactory">A factory to create new instances of the service implementation.</param>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Singleton(Type serviceType, Func<IServiceProvider, object> implementationFactory)
            {
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return Describe(serviceType, implementationFactory, ServiceLifetime.Singleton);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <typeparamref name="TService"/>, <paramref name="implementationInstance"/>,
            /// and the <see cref="ServiceLifetime.Scoped"/> lifetime.
            /// </summary>
            /// <typeparam name="TService">The type of the service.</typeparam>
            /// <param name="implementationInstance">The instance of the implementation.</param>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Singleton<TService>(TService implementationInstance)
                where TService : class
            {
                if (implementationInstance == null)
                {
                    throw new ArgumentNullException(nameof(implementationInstance));
                }
    
                return Singleton(typeof(TService), implementationInstance);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <paramref name="serviceType"/>, <paramref name="implementationInstance"/>,
            /// and the <see cref="ServiceLifetime.Scoped"/> lifetime.
            /// </summary>
            /// <param name="serviceType">The type of the service.</param>
            /// <param name="implementationInstance">The instance of the implementation.</param>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Singleton(Type serviceType, object implementationInstance)
            {
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                if (implementationInstance == null)
                {
                    throw new ArgumentNullException(nameof(implementationInstance));
                }
    
                return new ServiceDescriptor(serviceType, implementationInstance);
            }
    
            private static ServiceDescriptor Describe<TService, TImplementation>(ServiceLifetime lifetime)
                where TService : class
                where TImplementation : class, TService
            {
                return Describe(
                    typeof(TService),
                    typeof(TImplementation),
                    lifetime: lifetime);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <paramref name="serviceType"/>, <paramref name="implementationType"/>,
            /// and <paramref name="lifetime"/>.
            /// </summary>
            /// <param name="serviceType">The type of the service.</param>
            /// <param name="implementationType">The type of the implementation.</param>
            /// <param name="lifetime">The lifetime of the service.</param>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Describe(Type serviceType, Type implementationType, ServiceLifetime lifetime)
            {
                return new ServiceDescriptor(serviceType, implementationType, lifetime);
            }
    
            /// <summary>
            /// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
            /// <paramref name="serviceType"/>, <paramref name="implementationFactory"/>,
            /// and <paramref name="lifetime"/>.
            /// </summary>
            /// <param name="serviceType">The type of the service.</param>
            /// <param name="implementationFactory">A factory to create new instances of the service implementation.</param>
            /// <param name="lifetime">The lifetime of the service.</param>
            /// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
            public static ServiceDescriptor Describe(Type serviceType, Func<IServiceProvider, object> implementationFactory, ServiceLifetime lifetime)
            {
                return new ServiceDescriptor(serviceType, implementationFactory, lifetime);
            }
        }

    里面的静态方法Transient、Scoped、Singleton其实是创建ServiceDescriptor实例,方法名称表示对应的服务生命周期

    /// <summary>
        /// Specifies the lifetime of a service in an <see cref="IServiceCollection"/>.
        /// </summary>
        public enum ServiceLifetime
        {
            /// <summary>
            /// Specifies that a single instance of the service will be created.
            /// </summary>
            Singleton,
            /// <summary>
            /// Specifies that a new instance of the service will be created for each scope.
            /// </summary>
            /// <remarks>
            /// In ASP.NET Core applications a scope is created around each server request.
            /// </remarks>
            Scoped,
            /// <summary>
            /// Specifies that a new instance of the service will be created every time it is requested.
            /// </summary>
            Transient
        }

    服务的生命周期有三个:Singleton、Scoped、Transient

    IServiceCollection的默认扩展方法,这些方法使我们的服务注入变得更加简单

    public static class ServiceCollectionDescriptorExtensions
        {
            /// <summary>
            /// Adds the specified <paramref name="descriptor"/> to the <paramref name="collection"/>.
            /// </summary>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            /// <param name="descriptor">The <see cref="ServiceDescriptor"/> to add.</param>
            /// <returns>A reference to the current instance of <see cref="IServiceCollection"/>.</returns>
            public static IServiceCollection Add(
                this IServiceCollection collection,
                ServiceDescriptor descriptor)
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                if (descriptor == null)
                {
                    throw new ArgumentNullException(nameof(descriptor));
                }
    
                collection.Add(descriptor);
                return collection;
            }
    
            /// <summary>
            /// Adds a sequence of <see cref="ServiceDescriptor"/> to the <paramref name="collection"/>.
            /// </summary>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            /// <param name="descriptors">The <see cref="ServiceDescriptor"/>s to add.</param>
            /// <returns>A reference to the current instance of <see cref="IServiceCollection"/>.</returns>
            public static IServiceCollection Add(
                this IServiceCollection collection,
                IEnumerable<ServiceDescriptor> descriptors)
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                if (descriptors == null)
                {
                    throw new ArgumentNullException(nameof(descriptors));
                }
    
                foreach (var descriptor in descriptors)
                {
                    collection.Add(descriptor);
                }
    
                return collection;
            }
    
            /// <summary>
            /// Adds the specified <paramref name="descriptor"/> to the <paramref name="collection"/> if the
            /// service type hasn't already been registered.
            /// </summary>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            /// <param name="descriptor">The <see cref="ServiceDescriptor"/> to add.</param>
            public static void TryAdd(
                this IServiceCollection collection,
                ServiceDescriptor descriptor)
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                if (descriptor == null)
                {
                    throw new ArgumentNullException(nameof(descriptor));
                }
    
                if (!collection.Any(d => d.ServiceType == descriptor.ServiceType))
                {
                    collection.Add(descriptor);
                }
            }
    
            /// <summary>
            /// Adds the specified <paramref name="descriptors"/> to the <paramref name="collection"/> if the
            /// service type hasn't already been registered.
            /// </summary>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            /// <param name="descriptors">The <see cref="ServiceDescriptor"/>s to add.</param>
            public static void TryAdd(
                this IServiceCollection collection,
                IEnumerable<ServiceDescriptor> descriptors)
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                if (descriptors == null)
                {
                    throw new ArgumentNullException(nameof(descriptors));
                }
    
                foreach (var d in descriptors)
                {
                    collection.TryAdd(d);
                }
            }
    
            /// <summary>
            /// Adds the specified <paramref name="service"/> as a <see cref="ServiceLifetime.Transient"/> service
            /// to the <paramref name="collection"/> if the service type hasn't already been registered.
            /// </summary>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            /// <param name="service">The type of the service to register.</param>
            public static void TryAddTransient(
                this IServiceCollection collection,
                Type service)
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                if (service == null)
                {
                    throw new ArgumentNullException(nameof(service));
                }
    
                var descriptor = ServiceDescriptor.Transient(service, service);
                TryAdd(collection, descriptor);
            }
    
            /// <summary>
            /// Adds the specified <paramref name="service"/> as a <see cref="ServiceLifetime.Transient"/> service
            /// with the <paramref name="implementationType"/> implementation
            /// to the <paramref name="collection"/> if the service type hasn't already been registered.
            /// </summary>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            /// <param name="service">The type of the service to register.</param>
            /// <param name="implementationType">The implementation type of the service.</param>
            public static void TryAddTransient(
                this IServiceCollection collection,
                Type service,
                Type implementationType)
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                if (service == null)
                {
                    throw new ArgumentNullException(nameof(service));
                }
    
                if (implementationType == null)
                {
                    throw new ArgumentNullException(nameof(implementationType));
                }
    
                var descriptor = ServiceDescriptor.Transient(service, implementationType);
                TryAdd(collection, descriptor);
            }
    
            /// <summary>
            /// Adds the specified <paramref name="service"/> as a <see cref="ServiceLifetime.Transient"/> service
            /// using the factory specified in <paramref name="implementationFactory"/>
            /// to the <paramref name="collection"/> if the service type hasn't already been registered.
            /// </summary>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            /// <param name="service">The type of the service to register.</param>
            /// <param name="implementationFactory">The factory that creates the service.</param>
            public static void TryAddTransient(
                this IServiceCollection collection,
                Type service,
                Func<IServiceProvider, object> implementationFactory)
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                if (service == null)
                {
                    throw new ArgumentNullException(nameof(service));
                }
    
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                var descriptor = ServiceDescriptor.Transient(service, implementationFactory);
                TryAdd(collection, descriptor);
            }
    
            /// <summary>
            /// Adds the specified <typeparamref name="TService"/> as a <see cref="ServiceLifetime.Transient"/> service
            /// to the <paramref name="collection"/> if the service type hasn't already been registered.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            public static void TryAddTransient<TService>(this IServiceCollection collection)
                where TService : class
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                TryAddTransient(collection, typeof(TService), typeof(TService));
            }
    
            /// <summary>
            /// Adds the specified <typeparamref name="TService"/> as a <see cref="ServiceLifetime.Transient"/> service
            /// implementation type specified in <typeparamref name="TImplementation"/>
            /// to the <paramref name="collection"/> if the service type hasn't already been registered.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <typeparam name="TImplementation">The type of the implementation to use.</typeparam>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            public static void TryAddTransient<TService, TImplementation>(this IServiceCollection collection)
                where TService : class
                where TImplementation : class, TService
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                TryAddTransient(collection, typeof(TService), typeof(TImplementation));
            }
    
            /// <summary>
            /// Adds the specified <typeparamref name="TService"/> as a <see cref="ServiceLifetime.Transient"/> service
            /// using the factory specified in <paramref name="implementationFactory"/>
            /// to the <paramref name="services"/> if the service type hasn't already been registered.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <param name="services">The <see cref="IServiceCollection"/>.</param>
            /// <param name="implementationFactory">The factory that creates the service.</param>
            public static void TryAddTransient<TService>(
                this IServiceCollection services,
                Func<IServiceProvider, TService> implementationFactory)
                where TService : class
            {
                services.TryAdd(ServiceDescriptor.Transient(implementationFactory));
            }
    
            /// <summary>
            /// Adds the specified <paramref name="service"/> as a <see cref="ServiceLifetime.Scoped"/> service
            /// to the <paramref name="collection"/> if the service type hasn't already been registered.
            /// </summary>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            /// <param name="service">The type of the service to register.</param>
            public static void TryAddScoped(
                this IServiceCollection collection,
                Type service)
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                if (service == null)
                {
                    throw new ArgumentNullException(nameof(service));
                }
    
                var descriptor = ServiceDescriptor.Scoped(service, service);
                TryAdd(collection, descriptor);
            }
    
            /// <summary>
            /// Adds the specified <paramref name="service"/> as a <see cref="ServiceLifetime.Scoped"/> service
            /// with the <paramref name="implementationType"/> implementation
            /// to the <paramref name="collection"/> if the service type hasn't already been registered.
            /// </summary>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            /// <param name="service">The type of the service to register.</param>
            /// <param name="implementationType">The implementation type of the service.</param>
            public static void TryAddScoped(
                this IServiceCollection collection,
                Type service,
                Type implementationType)
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                if (service == null)
                {
                    throw new ArgumentNullException(nameof(service));
                }
    
                if (implementationType == null)
                {
                    throw new ArgumentNullException(nameof(implementationType));
                }
    
                var descriptor = ServiceDescriptor.Scoped(service, implementationType);
                TryAdd(collection, descriptor);
            }
    
            /// <summary>
            /// Adds the specified <paramref name="service"/> as a <see cref="ServiceLifetime.Scoped"/> service
            /// using the factory specified in <paramref name="implementationFactory"/>
            /// to the <paramref name="collection"/> if the service type hasn't already been registered.
            /// </summary>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            /// <param name="service">The type of the service to register.</param>
            /// <param name="implementationFactory">The factory that creates the service.</param>
            public static void TryAddScoped(
                this IServiceCollection collection,
                Type service,
                Func<IServiceProvider, object> implementationFactory)
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                if (service == null)
                {
                    throw new ArgumentNullException(nameof(service));
                }
    
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                var descriptor = ServiceDescriptor.Scoped(service, implementationFactory);
                TryAdd(collection, descriptor);
            }
    
            /// <summary>
            /// Adds the specified <typeparamref name="TService"/> as a <see cref="ServiceLifetime.Scoped"/> service
            /// to the <paramref name="collection"/> if the service type hasn't already been registered.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            public static void TryAddScoped<TService>(this IServiceCollection collection)
                where TService : class
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                TryAddScoped(collection, typeof(TService), typeof(TService));
            }
    
            /// <summary>
            /// Adds the specified <typeparamref name="TService"/> as a <see cref="ServiceLifetime.Scoped"/> service
            /// implementation type specified in <typeparamref name="TImplementation"/>
            /// to the <paramref name="collection"/> if the service type hasn't already been registered.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <typeparam name="TImplementation">The type of the implementation to use.</typeparam>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            public static void TryAddScoped<TService, TImplementation>(this IServiceCollection collection)
                where TService : class
                where TImplementation : class, TService
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                TryAddScoped(collection, typeof(TService), typeof(TImplementation));
            }
    
            /// <summary>
            /// Adds the specified <typeparamref name="TService"/> as a <see cref="ServiceLifetime.Scoped"/> service
            /// using the factory specified in <paramref name="implementationFactory"/>
            /// to the <paramref name="services"/> if the service type hasn't already been registered.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <param name="services">The <see cref="IServiceCollection"/>.</param>
            /// <param name="implementationFactory">The factory that creates the service.</param>
            public static void TryAddScoped<TService>(
                this IServiceCollection services,
                Func<IServiceProvider, TService> implementationFactory)
                where TService : class
            {
                services.TryAdd(ServiceDescriptor.Scoped(implementationFactory));
            }
    
            /// <summary>
            /// Adds the specified <paramref name="service"/> as a <see cref="ServiceLifetime.Singleton"/> service
            /// to the <paramref name="collection"/> if the service type hasn't already been registered.
            /// </summary>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            /// <param name="service">The type of the service to register.</param>
            public static void TryAddSingleton(
                this IServiceCollection collection,
                Type service)
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                if (service == null)
                {
                    throw new ArgumentNullException(nameof(service));
                }
    
                var descriptor = ServiceDescriptor.Singleton(service, service);
                TryAdd(collection, descriptor);
            }
    
            /// <summary>
            /// Adds the specified <paramref name="service"/> as a <see cref="ServiceLifetime.Singleton"/> service
            /// with the <paramref name="implementationType"/> implementation
            /// to the <paramref name="collection"/> if the service type hasn't already been registered.
            /// </summary>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            /// <param name="service">The type of the service to register.</param>
            /// <param name="implementationType">The implementation type of the service.</param>
            public static void TryAddSingleton(
                this IServiceCollection collection,
                Type service,
                Type implementationType)
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                if (service == null)
                {
                    throw new ArgumentNullException(nameof(service));
                }
    
                if (implementationType == null)
                {
                    throw new ArgumentNullException(nameof(implementationType));
                }
    
                var descriptor = ServiceDescriptor.Singleton(service, implementationType);
                TryAdd(collection, descriptor);
            }
    
            /// <summary>
            /// Adds the specified <paramref name="service"/> as a <see cref="ServiceLifetime.Singleton"/> service
            /// using the factory specified in <paramref name="implementationFactory"/>
            /// to the <paramref name="collection"/> if the service type hasn't already been registered.
            /// </summary>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            /// <param name="service">The type of the service to register.</param>
            /// <param name="implementationFactory">The factory that creates the service.</param>
            public static void TryAddSingleton(
                this IServiceCollection collection,
                Type service,
                Func<IServiceProvider, object> implementationFactory)
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                if (service == null)
                {
                    throw new ArgumentNullException(nameof(service));
                }
    
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                var descriptor = ServiceDescriptor.Singleton(service, implementationFactory);
                TryAdd(collection, descriptor);
            }
    
            /// <summary>
            /// Adds the specified <typeparamref name="TService"/> as a <see cref="ServiceLifetime.Singleton"/> service
            /// to the <paramref name="collection"/> if the service type hasn't already been registered.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            public static void TryAddSingleton<TService>(this IServiceCollection collection)
                where TService : class
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                TryAddSingleton(collection, typeof(TService), typeof(TService));
            }
    
            /// <summary>
            /// Adds the specified <typeparamref name="TService"/> as a <see cref="ServiceLifetime.Singleton"/> service
            /// implementation type specified in <typeparamref name="TImplementation"/>
            /// to the <paramref name="collection"/> if the service type hasn't already been registered.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <typeparam name="TImplementation">The type of the implementation to use.</typeparam>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            public static void TryAddSingleton<TService, TImplementation>(this IServiceCollection collection)
                where TService : class
                where TImplementation : class, TService
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                TryAddSingleton(collection, typeof(TService), typeof(TImplementation));
            }
    
            /// <summary>
            /// Adds the specified <typeparamref name="TService"/> as a <see cref="ServiceLifetime.Singleton"/> service
            /// with an instance specified in <paramref name="instance"/>
            /// to the <paramref name="collection"/> if the service type hasn't already been registered.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            /// <param name="instance">The instance of the service to add.</param>
            public static void TryAddSingleton<TService>(this IServiceCollection collection, TService instance)
                where TService : class
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                if (instance == null)
                {
                    throw new ArgumentNullException(nameof(instance));
                }
    
                var descriptor = ServiceDescriptor.Singleton(typeof(TService), instance);
                TryAdd(collection, descriptor);
            }
    
            /// <summary>
            /// Adds the specified <typeparamref name="TService"/> as a <see cref="ServiceLifetime.Singleton"/> service
            /// using the factory specified in <paramref name="implementationFactory"/>
            /// to the <paramref name="services"/> if the service type hasn't already been registered.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <param name="services">The <see cref="IServiceCollection"/>.</param>
            /// <param name="implementationFactory">The factory that creates the service.</param>
            public static void TryAddSingleton<TService>(
                this IServiceCollection services,
                Func<IServiceProvider, TService> implementationFactory)
                where TService : class
            {
                services.TryAdd(ServiceDescriptor.Singleton(implementationFactory));
            }
    
            /// <summary>
            /// Adds a <see cref="ServiceDescriptor"/> if an existing descriptor with the same
            /// <see cref="ServiceDescriptor.ServiceType"/> and an implementation that does not already exist
            /// in <paramref name="services."/>.
            /// </summary>
            /// <param name="services">The <see cref="IServiceCollection"/>.</param>
            /// <param name="descriptor">The <see cref="ServiceDescriptor"/>.</param>
            /// <remarks>
            /// Use <see cref="TryAddEnumerable(IServiceCollection, ServiceDescriptor)"/> when registering a service implementation of a
            /// service type that
            /// supports multiple registrations of the same service type. Using
            /// <see cref="Add(IServiceCollection, ServiceDescriptor)"/> is not idempotent and can add
            /// duplicate
            /// <see cref="ServiceDescriptor"/> instances if called twice. Using
            /// <see cref="TryAddEnumerable(IServiceCollection, ServiceDescriptor)"/> will prevent registration
            /// of multiple implementation types.
            /// </remarks>
            public static void TryAddEnumerable(
                this IServiceCollection services,
                ServiceDescriptor descriptor)
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (descriptor == null)
                {
                    throw new ArgumentNullException(nameof(descriptor));
                }
    
                var implementationType = descriptor.GetImplementationType();
    
                if (implementationType == typeof(object) ||
                    implementationType == descriptor.ServiceType)
                {
                    throw new ArgumentException(
                        Resources.FormatTryAddIndistinguishableTypeToEnumerable(
                            implementationType,
                            descriptor.ServiceType),
                        nameof(descriptor));
                }
    
                if (!services.Any(d =>
                                  d.ServiceType == descriptor.ServiceType &&
                                  d.GetImplementationType() == implementationType))
                {
                    services.Add(descriptor);
                }
            }
    
            /// <summary>
            /// Adds the specified <see cref="ServiceDescriptor"/>s if an existing descriptor with the same
            /// <see cref="ServiceDescriptor.ServiceType"/> and an implementation that does not already exist
            /// in <paramref name="services."/>.
            /// </summary>
            /// <param name="services">The <see cref="IServiceCollection"/>.</param>
            /// <param name="descriptors">The <see cref="ServiceDescriptor"/>s.</param>
            /// <remarks>
            /// Use <see cref="TryAddEnumerable(IServiceCollection, ServiceDescriptor)"/> when registering a service
            /// implementation of a service type that
            /// supports multiple registrations of the same service type. Using
            /// <see cref="Add(IServiceCollection, ServiceDescriptor)"/> is not idempotent and can add
            /// duplicate
            /// <see cref="ServiceDescriptor"/> instances if called twice. Using
            /// <see cref="TryAddEnumerable(IServiceCollection, ServiceDescriptor)"/> will prevent registration
            /// of multiple implementation types.
            /// </remarks>
            public static void TryAddEnumerable(
                this IServiceCollection services,
                IEnumerable<ServiceDescriptor> descriptors)
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (descriptors == null)
                {
                    throw new ArgumentNullException(nameof(descriptors));
                }
    
                foreach (var d in descriptors)
                {
                    services.TryAddEnumerable(d);
                }
            }
    
            /// <summary>
            /// Removes the first service in <see cref="IServiceCollection"/> with the same service type
            /// as <paramref name="descriptor"/> and adds <paramref name="descriptor"/> to the collection.
            /// </summary>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            /// <param name="descriptor">The <see cref="ServiceDescriptor"/> to replace with.</param>
            /// <returns>The <see cref="IServiceCollection"/> for chaining.</returns>
            public static IServiceCollection Replace(
                this IServiceCollection collection,
                ServiceDescriptor descriptor)
            {
                if (collection == null)
                {
                    throw new ArgumentNullException(nameof(collection));
                }
    
                if (descriptor == null)
                {
                    throw new ArgumentNullException(nameof(descriptor));
                }
    
                var registeredServiceDescriptor = collection.FirstOrDefault(s => s.ServiceType == descriptor.ServiceType);
                if (registeredServiceDescriptor != null)
                {
                    collection.Remove(registeredServiceDescriptor);
                }
    
                collection.Add(descriptor);
                return collection;
            }
    
            /// <summary>
            /// Removes all services of type <typeparamref name="T"/> in <see cref="IServiceCollection"/>.
            /// </summary>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            /// <returns>The <see cref="IServiceCollection"/> for chaining.</returns>
            public static IServiceCollection RemoveAll<T>(this IServiceCollection collection)
            {
                return RemoveAll(collection, typeof(T));
            }
    
            /// <summary>
            /// Removes all services of type <paramref name="serviceType"/> in <see cref="IServiceCollection"/>.
            /// </summary>
            /// <param name="collection">The <see cref="IServiceCollection"/>.</param>
            /// <param name="serviceType">The service type to remove.</param>
            /// <returns>The <see cref="IServiceCollection"/> for chaining.</returns>
            public static IServiceCollection RemoveAll(this IServiceCollection collection, Type serviceType)
            {
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                for (var i = collection.Count - 1; i >= 0; i--)
                {
                    var descriptor = collection[i];
                    if (descriptor.ServiceType == serviceType)
                    {
                        collection.RemoveAt(i);
                    }
                }
    
                return collection;
            }
        }

    注意一下几个方法:TryAddEnumerable、Replace

    /// <summary>
        /// Extension methods for adding services to an <see cref="IServiceCollection" />.
        /// </summary>
        public static class ServiceCollectionServiceExtensions
        {
            /// <summary>
            /// Adds a transient service of the type specified in <paramref name="serviceType"/> with an
            /// implementation of the type specified in <paramref name="implementationType"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <param name="serviceType">The type of the service to register.</param>
            /// <param name="implementationType">The implementation type of the service.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Transient"/>
            public static IServiceCollection AddTransient(
                this IServiceCollection services,
                Type serviceType,
                Type implementationType)
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                if (implementationType == null)
                {
                    throw new ArgumentNullException(nameof(implementationType));
                }
    
                return Add(services, serviceType, implementationType, ServiceLifetime.Transient);
            }
    
            /// <summary>
            /// Adds a transient service of the type specified in <paramref name="serviceType"/> with a
            /// factory specified in <paramref name="implementationFactory"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <param name="serviceType">The type of the service to register.</param>
            /// <param name="implementationFactory">The factory that creates the service.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Transient"/>
            public static IServiceCollection AddTransient(
                this IServiceCollection services,
                Type serviceType,
                Func<IServiceProvider, object> implementationFactory)
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return Add(services, serviceType, implementationFactory, ServiceLifetime.Transient);
            }
    
            /// <summary>
            /// Adds a transient service of the type specified in <typeparamref name="TService"/> with an
            /// implementation type specified in <typeparamref name="TImplementation"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <typeparam name="TImplementation">The type of the implementation to use.</typeparam>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Transient"/>
            public static IServiceCollection AddTransient<TService, TImplementation>(this IServiceCollection services)
                where TService : class
                where TImplementation : class, TService
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                return services.AddTransient(typeof(TService), typeof(TImplementation));
            }
    
            /// <summary>
            /// Adds a transient service of the type specified in <paramref name="serviceType"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <param name="serviceType">The type of the service to register and the implementation to use.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Transient"/>
            public static IServiceCollection AddTransient(
                this IServiceCollection services,
                Type serviceType)
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                return services.AddTransient(serviceType, serviceType);
            }
    
            /// <summary>
            /// Adds a transient service of the type specified in <typeparamref name="TService"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Transient"/>
            public static IServiceCollection AddTransient<TService>(this IServiceCollection services)
                where TService : class
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                return services.AddTransient(typeof(TService));
            }
    
            /// <summary>
            /// Adds a transient service of the type specified in <typeparamref name="TService"/> with a
            /// factory specified in <paramref name="implementationFactory"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <param name="implementationFactory">The factory that creates the service.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Transient"/>
            public static IServiceCollection AddTransient<TService>(
                this IServiceCollection services,
                Func<IServiceProvider, TService> implementationFactory)
                where TService : class
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return services.AddTransient(typeof(TService), implementationFactory);
            }
    
            /// <summary>
            /// Adds a transient service of the type specified in <typeparamref name="TService"/> with an
            /// implementation type specified in <typeparamref name="TImplementation" /> using the
            /// factory specified in <paramref name="implementationFactory"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <typeparam name="TImplementation">The type of the implementation to use.</typeparam>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <param name="implementationFactory">The factory that creates the service.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Transient"/>
            public static IServiceCollection AddTransient<TService, TImplementation>(
                this IServiceCollection services,
                Func<IServiceProvider, TImplementation> implementationFactory)
                where TService : class
                where TImplementation : class, TService
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return services.AddTransient(typeof(TService), implementationFactory);
            }
    
    
    
            /// <summary>
            /// Adds a scoped service of the type specified in <paramref name="serviceType"/> with an
            /// implementation of the type specified in <paramref name="implementationType"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <param name="serviceType">The type of the service to register.</param>
            /// <param name="implementationType">The implementation type of the service.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Scoped"/>
            public static IServiceCollection AddScoped(
                this IServiceCollection services,
                Type serviceType,
                Type implementationType)
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                if (implementationType == null)
                {
                    throw new ArgumentNullException(nameof(implementationType));
                }
    
                return Add(services, serviceType, implementationType, ServiceLifetime.Scoped);
            }
    
            /// <summary>
            /// Adds a scoped service of the type specified in <paramref name="serviceType"/> with a
            /// factory specified in <paramref name="implementationFactory"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <param name="serviceType">The type of the service to register.</param>
            /// <param name="implementationFactory">The factory that creates the service.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Scoped"/>
            public static IServiceCollection AddScoped(
                this IServiceCollection services,
                Type serviceType,
                Func<IServiceProvider, object> implementationFactory)
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return Add(services, serviceType, implementationFactory, ServiceLifetime.Scoped);
            }
    
            /// <summary>
            /// Adds a scoped service of the type specified in <typeparamref name="TService"/> with an
            /// implementation type specified in <typeparamref name="TImplementation"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <typeparam name="TImplementation">The type of the implementation to use.</typeparam>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Scoped"/>
            public static IServiceCollection AddScoped<TService, TImplementation>(this IServiceCollection services)
                where TService : class
                where TImplementation : class, TService
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                return services.AddScoped(typeof(TService), typeof(TImplementation));
            }
    
            /// <summary>
            /// Adds a scoped service of the type specified in <paramref name="serviceType"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <param name="serviceType">The type of the service to register and the implementation to use.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Scoped"/>
            public static IServiceCollection AddScoped(
                this IServiceCollection services,
                Type serviceType)
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                return services.AddScoped(serviceType, serviceType);
            }
    
            /// <summary>
            /// Adds a scoped service of the type specified in <typeparamref name="TService"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Scoped"/>
            public static IServiceCollection AddScoped<TService>(this IServiceCollection services)
                where TService : class
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                return services.AddScoped(typeof(TService));
            }
    
            /// <summary>
            /// Adds a scoped service of the type specified in <typeparamref name="TService"/> with a
            /// factory specified in <paramref name="implementationFactory"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <param name="implementationFactory">The factory that creates the service.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Scoped"/>
            public static IServiceCollection AddScoped<TService>(
                this IServiceCollection services,
                Func<IServiceProvider, TService> implementationFactory)
                where TService : class
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return services.AddScoped(typeof(TService), implementationFactory);
            }
    
            /// <summary>
            /// Adds a scoped service of the type specified in <typeparamref name="TService"/> with an
            /// implementation type specified in <typeparamref name="TImplementation" /> using the
            /// factory specified in <paramref name="implementationFactory"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <typeparam name="TImplementation">The type of the implementation to use.</typeparam>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <param name="implementationFactory">The factory that creates the service.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Scoped"/>
            public static IServiceCollection AddScoped<TService, TImplementation>(
                this IServiceCollection services,
                Func<IServiceProvider, TImplementation> implementationFactory)
                where TService : class
                where TImplementation : class, TService
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return services.AddScoped(typeof(TService), implementationFactory);
            }
    
    
            /// <summary>
            /// Adds a singleton service of the type specified in <paramref name="serviceType"/> with an
            /// implementation of the type specified in <paramref name="implementationType"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <param name="serviceType">The type of the service to register.</param>
            /// <param name="implementationType">The implementation type of the service.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Singleton"/>
            public static IServiceCollection AddSingleton(
                this IServiceCollection services,
                Type serviceType,
                Type implementationType)
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                if (implementationType == null)
                {
                    throw new ArgumentNullException(nameof(implementationType));
                }
    
                return Add(services, serviceType, implementationType, ServiceLifetime.Singleton);
            }
    
            /// <summary>
            /// Adds a singleton service of the type specified in <paramref name="serviceType"/> with a
            /// factory specified in <paramref name="implementationFactory"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <param name="serviceType">The type of the service to register.</param>
            /// <param name="implementationFactory">The factory that creates the service.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Singleton"/>
            public static IServiceCollection AddSingleton(
                this IServiceCollection services,
                Type serviceType,
                Func<IServiceProvider, object> implementationFactory)
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return Add(services, serviceType, implementationFactory, ServiceLifetime.Singleton);
            }
    
            /// <summary>
            /// Adds a singleton service of the type specified in <typeparamref name="TService"/> with an
            /// implementation type specified in <typeparamref name="TImplementation"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <typeparam name="TImplementation">The type of the implementation to use.</typeparam>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Singleton"/>
            public static IServiceCollection AddSingleton<TService, TImplementation>(this IServiceCollection services)
                where TService : class
                where TImplementation : class, TService
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                return services.AddSingleton(typeof(TService), typeof(TImplementation));
            }
    
            /// <summary>
            /// Adds a singleton service of the type specified in <paramref name="serviceType"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <param name="serviceType">The type of the service to register and the implementation to use.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Singleton"/>
            public static IServiceCollection AddSingleton(
                this IServiceCollection services,
                Type serviceType)
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                return services.AddSingleton(serviceType, serviceType);
            }
    
            /// <summary>
            /// Adds a singleton service of the type specified in <typeparamref name="TService"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Singleton"/>
            public static IServiceCollection AddSingleton<TService>(this IServiceCollection services)
                where TService : class
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                return services.AddSingleton(typeof(TService));
            }
    
            /// <summary>
            /// Adds a singleton service of the type specified in <typeparamref name="TService"/> with a
            /// factory specified in <paramref name="implementationFactory"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <param name="implementationFactory">The factory that creates the service.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Singleton"/>
            public static IServiceCollection AddSingleton<TService>(
                this IServiceCollection services,
                Func<IServiceProvider, TService> implementationFactory)
                where TService : class
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return services.AddSingleton(typeof(TService), implementationFactory);
            }
    
            /// <summary>
            /// Adds a singleton service of the type specified in <typeparamref name="TService"/> with an
            /// implementation type specified in <typeparamref name="TImplementation" /> using the
            /// factory specified in <paramref name="implementationFactory"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <typeparam name="TService">The type of the service to add.</typeparam>
            /// <typeparam name="TImplementation">The type of the implementation to use.</typeparam>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <param name="implementationFactory">The factory that creates the service.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Singleton"/>
            public static IServiceCollection AddSingleton<TService, TImplementation>(
                this IServiceCollection services,
                Func<IServiceProvider, TImplementation> implementationFactory)
                where TService : class
                where TImplementation : class, TService
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (implementationFactory == null)
                {
                    throw new ArgumentNullException(nameof(implementationFactory));
                }
    
                return services.AddSingleton(typeof(TService), implementationFactory);
            }
    
            /// <summary>
            /// Adds a singleton service of the type specified in <paramref name="serviceType"/> with an
            /// instance specified in <paramref name="implementationInstance"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <param name="serviceType">The type of the service to register.</param>
            /// <param name="implementationInstance">The instance of the service.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Singleton"/>
            public static IServiceCollection AddSingleton(
                this IServiceCollection services,
                Type serviceType,
                object implementationInstance)
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                if (implementationInstance == null)
                {
                    throw new ArgumentNullException(nameof(implementationInstance));
                }
    
                var serviceDescriptor = new ServiceDescriptor(serviceType, implementationInstance);
                services.Add(serviceDescriptor);
                return services;
            }
    
            /// <summary>
            /// Adds a singleton service of the type specified in <typeparamref name="TService" /> with an
            /// instance specified in <paramref name="implementationInstance"/> to the
            /// specified <see cref="IServiceCollection"/>.
            /// </summary>
            /// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
            /// <param name="implementationInstance">The instance of the service.</param>
            /// <returns>A reference to this instance after the operation has completed.</returns>
            /// <seealso cref="ServiceLifetime.Singleton"/>
            public static IServiceCollection AddSingleton<TService>(
                this IServiceCollection services,
                TService implementationInstance)
                where TService : class
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (implementationInstance == null)
                {
                    throw new ArgumentNullException(nameof(implementationInstance));
                }
    
                return services.AddSingleton(typeof(TService), implementationInstance);
            }
    
            private static IServiceCollection Add(
                IServiceCollection collection,
                Type serviceType,
                Type implementationType,
                ServiceLifetime lifetime)
            {
                var descriptor = new ServiceDescriptor(serviceType, implementationType, lifetime);
                collection.Add(descriptor);
                return collection;
            }
    
            private static IServiceCollection Add(
                IServiceCollection collection,
                Type serviceType,
                Func<IServiceProvider, object> implementationFactory,
                ServiceLifetime lifetime)
            {
                var descriptor = new ServiceDescriptor(serviceType, implementationFactory, lifetime);
                collection.Add(descriptor);
                return collection;
            }
        }

    IServiceProvider扩展方法

    /// <summary>
        /// Extension methods for getting services from an <see cref="IServiceProvider" />.
        /// </summary>
        public static class ServiceProviderServiceExtensions
        {
            /// <summary>
            /// Get service of type <typeparamref name="T"/> from the <see cref="IServiceProvider"/>.
            /// </summary>
            /// <typeparam name="T">The type of service object to get.</typeparam>
            /// <param name="provider">The <see cref="IServiceProvider"/> to retrieve the service object from.</param>
            /// <returns>A service object of type <typeparamref name="T"/> or null if there is no such service.</returns>
            public static T GetService<T>(this IServiceProvider provider)
            {
                if (provider == null)
                {
                    throw new ArgumentNullException(nameof(provider));
                }
    
                return (T)provider.GetService(typeof(T));
            }
    
            /// <summary>
            /// Get service of type <paramref name="serviceType"/> from the <see cref="IServiceProvider"/>.
            /// </summary>
            /// <param name="provider">The <see cref="IServiceProvider"/> to retrieve the service object from.</param>
            /// <param name="serviceType">An object that specifies the type of service object to get.</param>
            /// <returns>A service object of type <paramref name="serviceType"/>.</returns>
            /// <exception cref="System.InvalidOperationException">There is no service of type <paramref name="serviceType"/>.</exception>
            public static object GetRequiredService(this IServiceProvider provider, Type serviceType)
            {
                if (provider == null)
                {
                    throw new ArgumentNullException(nameof(provider));
                }
    
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                var requiredServiceSupportingProvider = provider as ISupportRequiredService;
                if (requiredServiceSupportingProvider != null)
                {
                    return requiredServiceSupportingProvider.GetRequiredService(serviceType);
                }
    
                var service = provider.GetService(serviceType);
                if (service == null)
                {
                    throw new InvalidOperationException(Resources.FormatNoServiceRegistered(serviceType));
                }
    
                return service;
            }
    
            /// <summary>
            /// Get service of type <typeparamref name="T"/> from the <see cref="IServiceProvider"/>.
            /// </summary>
            /// <typeparam name="T">The type of service object to get.</typeparam>
            /// <param name="provider">The <see cref="IServiceProvider"/> to retrieve the service object from.</param>
            /// <returns>A service object of type <typeparamref name="T"/>.</returns>
            /// <exception cref="System.InvalidOperationException">There is no service of type <typeparamref name="T"/>.</exception>
            public static T GetRequiredService<T>(this IServiceProvider provider)
            {
                if (provider == null)
                {
                    throw new ArgumentNullException(nameof(provider));
                }
    
                return (T)provider.GetRequiredService(typeof(T));
            }
    
            /// <summary>
            /// Get an enumeration of services of type <typeparamref name="T"/> from the <see cref="IServiceProvider"/>.
            /// </summary>
            /// <typeparam name="T">The type of service object to get.</typeparam>
            /// <param name="provider">The <see cref="IServiceProvider"/> to retrieve the services from.</param>
            /// <returns>An enumeration of services of type <typeparamref name="T"/>.</returns>
            public static IEnumerable<T> GetServices<T>(this IServiceProvider provider)
            {
                if (provider == null)
                {
                    throw new ArgumentNullException(nameof(provider));
                }
    
                return provider.GetRequiredService<IEnumerable<T>>();
            }
    
            /// <summary>
            /// Get an enumeration of services of type <paramref name="serviceType"/> from the <see cref="IServiceProvider"/>.
            /// </summary>
            /// <param name="provider">The <see cref="IServiceProvider"/> to retrieve the services from.</param>
            /// <param name="serviceType">An object that specifies the type of service object to get.</param>
            /// <returns>An enumeration of services of type <paramref name="serviceType"/>.</returns>
            public static IEnumerable<object> GetServices(this IServiceProvider provider, Type serviceType)
            {
                if (provider == null)
                {
                    throw new ArgumentNullException(nameof(provider));
                }
    
                if (serviceType == null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
    
                var genericEnumerable = typeof(IEnumerable<>).MakeGenericType(serviceType);
                return (IEnumerable<object>)provider.GetRequiredService(genericEnumerable);
            }
    
            /// <summary>
            /// Creates a new <see cref="IServiceScope"/> that can be used to resolve scoped services.
            /// </summary>
            /// <param name="provider">The <see cref="IServiceProvider"/> to create the scope from.</param>
            /// <returns>A <see cref="IServiceScope"/> that can be used to resolve scoped services.</returns>
            public static IServiceScope CreateScope(this IServiceProvider provider)
            {
                return provider.GetRequiredService<IServiceScopeFactory>().CreateScope();
            }
        }

    本文章主要分析下netcore依赖注入的几个接口和重要的类ServiceDescriptor,下篇再分析下具体的实现

  • 相关阅读:
    LeetCode 32. 最长有效括号(Longest Valid Parentheses)
    LeetCode 141. 环形链表(Linked List Cycle)
    LeetCode 160. 相交链表(Intersection of Two Linked Lists)
    LeetCode 112. 路径总和(Path Sum)
    LeetCode 124. 二叉树中的最大路径和(Binary Tree Maximum Path Sum)
    LightGBM新特性总结
    sql service 事务与锁
    C#泛型实例详解
    C# 中的委托和事件(详解)
    C# DateTime日期格式化
  • 原文地址:https://www.cnblogs.com/lanpingwang/p/12539116.html
Copyright © 2011-2022 走看看