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,下篇再分析下具体的实现

  • 相关阅读:
    Python Day7(相关补充)
    Python Day7
    Python Day6
    Python Day5
    Python Day4
    Python Day3
    Python Day2
    Python Day1
    复杂装饰器原理分析
    Unity 坐标
  • 原文地址:https://www.cnblogs.com/lanpingwang/p/12539116.html
Copyright © 2011-2022 走看看