• 重新整理.net core 计1400篇[九] (.net core 中的依赖注入的服务的消费)


    前言

    包含服务注册信息IServiceCollection 集合最终被用来创建作为依赖注入容器的IServiceProvider 对象。

    当需要创建某个服务实例的时候(服务消费),我们通过指定服务类型调用IServiceProvider 接口GetService 方法即可。

    那么来看下和IServiceProvider 相关的东西吧。

    IServiceProvider

    这里面只有一个提供服务的方法:

    /// <summary>Defines a mechanism for retrieving a service object; that is, an object that provides custom support to other objects.</summary>
    public interface IServiceProvider
    {
    	/// <summary>Gets the service object of the specified type.</summary>
    	/// <param name="serviceType">An object that specifies the type of service object to get.</param>
    	/// <returns>A service object of type <paramref name="serviceType">serviceType</paramref>.  
    	///  -or-  
    	///  null if there is no service object of type <paramref name="serviceType">serviceType</paramref>.</returns>
    	object GetService(Type serviceType);
    }
    

    在创建IServiceProvider的对象创建上,有三个构造函数:

    public static class ServiceCollectionContainerBuilderExtensions
    {
    	/// <summary>
    	/// Creates a <see cref="T:Microsoft.Extensions.DependencyInjection.ServiceProvider" /> containing services from the provided <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" />.
    	/// </summary>
    	/// <param name="services">The <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" /> containing service descriptors.</param>
    	/// <returns>The <see cref="T:Microsoft.Extensions.DependencyInjection.ServiceProvider" />.</returns>
    	public static ServiceProvider BuildServiceProvider(this IServiceCollection services)
    	{
    		return services.BuildServiceProvider(ServiceProviderOptions.Default);
    	}
    
    	/// <summary>
    	/// Creates a <see cref="T:Microsoft.Extensions.DependencyInjection.ServiceProvider" /> containing services from the provided <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" />
    	/// optionally enabling scope validation.
    	/// </summary>
    	/// <param name="services">The <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" /> containing service descriptors.</param>
    	/// <param name="validateScopes">
    	/// <c>true</c> to perform check verifying that scoped services never gets resolved from root provider; otherwise <c>false</c>.
    	/// </param>
    	/// <returns>The <see cref="T:Microsoft.Extensions.DependencyInjection.ServiceProvider" />.</returns>
    	public static ServiceProvider BuildServiceProvider(this IServiceCollection services, bool validateScopes)
    	{
    		return services.BuildServiceProvider(new ServiceProviderOptions
    		{
    			ValidateScopes = validateScopes
    		});
    	}
    
    	/// <summary>
    	/// Creates a <see cref="T:Microsoft.Extensions.DependencyInjection.ServiceProvider" /> containing services from the provided <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" />
    	/// optionally enabling scope validation.
    	/// </summary>
    	/// <param name="services">The <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" /> containing service descriptors.</param>
    	/// <param name="options">
    	/// Configures various service provider behaviors.
    	/// </param>
    	/// <returns>The <see cref="T:Microsoft.Extensions.DependencyInjection.ServiceProvider" />.</returns>
    	public static ServiceProvider BuildServiceProvider(this IServiceCollection services, ServiceProviderOptions options)
    	{
    		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
    		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
    		if (services == null)
    		{
    			throw new ArgumentNullException("services");
    		}
    		if (options == null)
    		{
    			throw new ArgumentNullException("options");
    		}
    		return new ServiceProvider((IEnumerable<ServiceDescriptor>)services, options);
    	}
    }
    

    我们看到无论其如何构造,那么都有一个ServiceProviderOptions配置类。

    这个配置我前面8中解释过,就是对注入服务的范围检测。

    那么还有一个重要的问题,难道我们只能根据getservice 去获取服务对象?来看看获取服务的扩展。

    查看ServiceProviderServiceExtensions类:

    里面有一些:

    public static T GetService<T>(this IServiceProvider provider)
    {
    	//IL_0008: Unknown result type (might be due to invalid IL or missing references)
    	if (provider == null)
    	{
    		throw new ArgumentNullException("provider");
    	}
    	return (T)provider.GetService(Type.GetTypeFromHandle(typeof(T).TypeHandle));
    }
    
    /// <summary>
    /// Get service of type <paramref name="serviceType" /> from the <see cref="T:System.IServiceProvider" />.
    /// </summary>
    /// <param name="provider">The <see cref="T:System.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="T:System.InvalidOperationException">There is no service of type <paramref name="serviceType" />.</exception>
    public static object GetRequiredService(this IServiceProvider provider, Type serviceType)
    {
    	//IL_0008: Unknown result type (might be due to invalid IL or missing references)
    	//IL_001c: Unknown result type (might be due to invalid IL or missing references)
    	//IL_0044: Unknown result type (might be due to invalid IL or missing references)
    	if (provider == null)
    	{
    		throw new ArgumentNullException("provider");
    	}
    	if (serviceType == (Type)null)
    	{
    		throw new ArgumentNullException("serviceType");
    	}
    	ISupportRequiredService supportRequiredService = provider as ISupportRequiredService;
    	if (supportRequiredService != null)
    	{
    		return supportRequiredService.GetRequiredService(serviceType);
    	}
    	object 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="T:System.IServiceProvider" />.
    /// </summary>
    /// <typeparam name="T">The type of service object to get.</typeparam>
    /// <param name="provider">The <see cref="T:System.IServiceProvider" /> to retrieve the service object from.</param>
    /// <returns>A service object of type <typeparamref name="T" />.</returns>
    /// <exception cref="T:System.InvalidOperationException">There is no service of type <typeparamref name="T" />.</exception>
    public static T GetRequiredService<T>(this IServiceProvider provider)
    {
    	//IL_0008: Unknown result type (might be due to invalid IL or missing references)
    	if (provider == null)
    	{
    		throw new ArgumentNullException("provider");
    	}
    	return (T)provider.GetRequiredService(Type.GetTypeFromHandle(typeof(T).TypeHandle));
    }
    
    /// <summary>
    /// Get an enumeration of services of type <typeparamref name="T" /> from the <see cref="T:System.IServiceProvider" />.
    /// </summary>
    /// <typeparam name="T">The type of service object to get.</typeparam>
    /// <param name="provider">The <see cref="T:System.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)
    {
    	//IL_0008: Unknown result type (might be due to invalid IL or missing references)
    	if (provider == null)
    	{
    		throw new ArgumentNullException("provider");
    	}
    	return provider.GetRequiredService<IEnumerable<T>>();
    }
    

    其余的可以自己去查看。

    服务的创建

    我们知道服务的创建一般都是ioc自动选择的,那么假如我们一个class 里面有多个构造函数,那么会选择哪一个呢?

    public interface IFoo { }
    public interface IBar { }
    public interface IBaz { }
    public interface IQux { }
    
    public class Foo : IFoo { }
    public class Bar : IBar { }
    public class Baz : IBaz { }
    public class Qux : IQux
    {
    	public Qux(IFoo foo) => Console.WriteLine("Selected constructor: Qux(IFoo)");
    	public Qux(IFoo foo, IBar bar) => Console.WriteLine("Selected constructor: Qux(IFoo, IBar)");
    	public Qux(IFoo foo, IBar bar, IBaz baz) => Console.WriteLine("Selected constructor: Qux(IFoo, IBar, IBaz)");
    }
    static void Main()
    {
    	new ServiceCollection()
    		.AddTransient<IFoo, Foo>()
    		.AddTransient<IBar, Bar>()
    		.AddTransient<IQux, Qux>()
    		.BuildServiceProvider()
    		.GetServices<IQux>();
    	Console.ReadKey();
    }
    

    上面Qux有三个控制类,那么选择哪一个呢?

    看下结果:

    那么为什么会是这一个呢?

    第一:IBaz类型没有注册,那么会排除掉Qux(IFoo foo, IBar bar, IBaz baz)

    第二就是里面的一个规则:每一个候选构造参数类型的集合都是这个构造函数参数类型的子集。

    好的,那么好了,剩下:Qux(IFoo foo, IBar bar) 包含了Qux(IFoo foo) 那么就是Qux(IFoo foo, IBar bar),如果没有包含全部子集的那么就会报错。

    Qux(IFoo foo, IBar bar) 也就是超集的意思。

    改一下:

    public interface IFoo { }
    public interface IBar { }
    public interface IBaz { }
    public interface IQux { }
    
    public class Foo : IFoo { }
    public class Bar : IBar { }
    public class Baz : IBaz { }
    public class Qux : IQux
    {
    	public Qux(IFoo foo, IBaz baz) => Console.WriteLine("Selected constructor: Qux(IFoo, IBar)");
    	public Qux(IFoo foo, IBar bar) => Console.WriteLine("Selected constructor: Qux(IFoo, IBar, IBaz)");
    }
    static void Main()
    {
    	new ServiceCollection()
    		.AddTransient<IFoo, Foo>()
    		.AddTransient<IBar, Bar>()
    		.AddTransient<IBaz,Baz>()
    		.AddTransient<IQux, Qux>()
    		.BuildServiceProvider()
    		.GetServices<IQux>();
    	Console.ReadKey();
    }
    

    这时候报错为:

    下一节

    服务的生命周期

  • 相关阅读:
    UVa 1592 Database(巧用map)
    TZOJ 4746 Xiangqi(模拟棋盘数组)
    TZOJ 1545 Hurdles of 110m(01背包dp)
    TZOJ 2754 Watering Hole(最小生成树Kruskal)
    TZOJ 1242 求出前m大的数(预处理)
    TZOJ 5280 搜索引擎(模拟字符串)
    TZOJ 4865 统计单词数(模拟字符串)
    TZOJ 5279 马拉松比赛(广搜)
    [luogu4735]最大异或和
    小奇回地球
  • 原文地址:https://www.cnblogs.com/aoximin/p/12931943.html
Copyright © 2020-2023  润新知