当参数类型为Action <someobject>时,实例化对象的内容

时间:2018-04-15 18:23:28

标签: c# asp.net-core

我正在查看github上的.net核心2.0代码,以便在文章中对某些代码进行取消混淆并遇到this

public static IMvcBuilder AddRazorPagesOptions(
        this IMvcBuilder builder,
        Action<RazorPagesOptions> setupAction)
{ }

经过审核,似乎没有明确地实例化RazorPagesOptions类型的对象。我遇到的问题是RazorPageOptions类型的对象是如何实例化的?

1 个答案:

答案 0 :(得分:3)

这与依赖注入模式的ASP.NET Core实现有关。 Daisy在评论中指出的确切表明:

builder.Services.Configure(setupAction)

builderIMvcBuilderbuilder.ServicesIServiceCollection,也就是说,设置为在asp-net应用程序中可用的所有服务的主列表。在Startup.cs中设置了FoobarService?然后,IFoobarService的定义可能会位于ServiceCollection中。等

ServiceCollection附加了大量扩展方法,可以更轻松地添加新服务。它还有.BuildServiceProvider(),它接受​​所有已注册的定义,并创建一个服务工厂/提供者/缓存/解析器/事物,您/ asp以后可以使用它来获取这些服务的实际实例。

然后,除了服务注册和建立工厂之外,由于“每个人都习惯”在Startup.cs中设置ServiceCollection成为焦点的东西这一事实,还有一个自定义配置进一步的细节,通过ServiceCollection或姐妹对象上的更多扩展方法,可能需要在Startup.cs中提供服务。

现在,ASP.NET Core MVC有一个用于处理应用程序配置的模块。它的设计是这样的,你定义一个类,通常称为WhateverOptions,它将包含与Whatever相关的配置的某些部分,并且可以通过任何服务稍后通过要求注入来检索它。但是,由于我们将配置拆分为许多或多或少的上下文对象,如果我们将它们全部实例化(在一个地方?)并填充它们(在一个地方?!),那将是一个巨大的混乱。为方便起见,所有这些都将由框架创建。剩下的问题是,谁将填写实际设置。

..这与你找到的很接近。这一行:

builder.Services.Configure(setupAction)

采取Action(带有1个参数的仿函数:Razor-Options)并将其注册到任何服务的大包中。它被注册为RazorPagesOptions的设置源。作为副作用,IoC容器还了解到某些服务可能需要RazorPagesOptions

稍后,在运行时,当有人要求提供服务实例时,如果服务需要RazorPagesOptions,则容器会检查它是否已准备好。如果没有,则创建那些RazorPagesOptions的实例(可能是单例模式),但当然它最初是空的。然后,它将通过所有已注册的设置源。依次调用每个这样的源,每个源都获取RazorPagesOptions实例,并且每个源都有机会用它们的部分设置填充它。最后,当所有的都运行时,RazorPagesOptions的实例(可能是缓存然后......)被传递给需要它的服务。

我还没有说过的一件事是Action<RazorPagesOptions>的实例来自哪里。它可能来自Startup.cs。在那里你有一条类似于:

的线
services
    .AddMvc()  // registers MVC services in IoCC and gets you the IMvcBuilder
    .AddRazorPagesOptions(options => 
{
    options.RootDirectory = "....";
    options.Conventions.Add(new FooConvention....);
    ...
});

options => {..}Action<RazorPagesOptions>,将传递给AddRazorPagesOptions,然后传递给serviceCollection.Configure,并将其注册为RazorPagesOptions的实际设置源。< / p>

外卖:

  • 假设您编写了一个ASP.NET Core MVC应用程序,那么它在Startup.cs中的代码创建了Action&lt;&gt;的实例。委托 - 或者当你在调用AddRazorPagesOptions方法时编写lambda时实际上“编译器做了”
  • 此委托(可能)不会立即调用,但存储以供以后使用
  • 在应用程序运行时生命周期的某个时间,ASP.NET Core MVC框架会注意到需要RazorPagesOptions并将创建实例。可能是通过Reflection或Activator.CreateInstance(Type),所以你不会在任何地方找到new RazorPagesOptions()
  • 所有这些都是特定于ASP.NET Core MVC,而不是纯粹的C#
  • 其他库/框架/ IoCCs / etc中存在类似的机制和模式
  • 和最后的注意事项 - 我试图以“易于理解的方式”编写它,而不是100%精确。我在这里写的很多东西“有点不真实”,但恕我直言,足够接近