【问题标题】:What instantiates the object when a parameter type of Action<SomeObject>当参数类型为 Action<SomeObject> 时,什么实例化对象
【发布时间】:2018-09-25 11:42:19
【问题描述】:

我正在查看 github 上的 .net core 2.0 代码以对一篇文章中的一些代码进行解密,结果遇到了this

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

经过审查,RazorPagesOptions 类型的对象似乎从未被显式实例化。我的问题是 RazorPageOptions 类型的对象是如何实例化的?

【问题讨论】:

  • 该代码只是将操作传递给builder.Services.Configure(setupAction),因此可能会创建选项或将其传递给执行此操作的else
  • (但从根本上说,您需要根据您的标题确定您的问题是 一般 问题,还是您对 Razor/ASP.NET 感兴趣关于 RazorPagesOptions 的核心特定问题。)
  • 这是一个普遍的问题。据我所知,该对象正在为我实例化。我在控制台应用程序中运行了一个单独的测试尝试这种方法,没有创建对象的实例,并使用非静态方法,它工作正常。使用这种方法似乎为我创建了一个对象的实例。
  • 问题是当我将它用作没有返回类型的委托的参数的一部分时,我是否会自动获取对象的实例
  • 不,不会自动创建实例。听起来这将是一个更容易回答的问题,如果您对其进行编辑以包含您的控制台应用程序,其中包含您不了解的方面的详细信息,并删除了 Razor Pages 部分。

标签: c# asp.net-core


【解决方案1】:

这与依赖注入模式的 ASP.NET Core 实现有关。 Daisy 在 cmets 中指出的正是:

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)并将其注册到 big-bag-of-all-infos-on-any-service 中。它被注册为 RazorPagesOptions 的设置源。作为副作用,IoC 容器还获悉某些服务可能需要 RazorPagesOptions

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

我还没有说的一件事是Action&lt;RazorPagesOptions&gt; 的实例是从哪里来的。它可能来自 Startup.cs。在某处,您会有类似于以下内容的行:

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

options =&gt; {..}Action&lt;RazorPagesOptions&gt;,将传递给 AddRazorPagesOptions,然后传递给 serviceCollection.Configure,并将注册为 RazorPagesOptions 的实际设置源。

要点:

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

【讨论】:

  • 这是一个很好的解释,彻底解决了我的困惑。我很抱歉没有认识到这个问题确实应该被标记为 asp.net mvc-core。谢谢你们。
  • “ASP MVC”和“ASPMVCCORE”不存在,请写出正确的名称:ASP.NET Core 是这里讨论的唯一产品。另外,IoC 是模式,你说的是容器
  • 我引用的是堆栈溢出标签,而不是产品。更具体地说,我所说的是这个问题可能应该用 asp.net-core-mvc 标记。
  • @CamiloTerevinto:我已经纠正了你指出的所有事情。但是,您有点错误:有一个 ASP.NET Core 作为通用平台/框架,还有一个 ASP.NET Core MVC - 一个提供 MVC 服务的插件/模块,它通过以下方式进入文本范围AddMvc()+IMvcBuilder。什么是单独的产品,什么不是,这是一个有争议的事情,取决于你想要讨论它的层次。对于营销,当然,这都是 ASP.NET Core。对于其他用途,单独的程序集或 nuget 可能是单独的产品,我将 ASP.NET Core MVC 视为构建在 ASP.NET Core 之上的单独事物。
  • @quetzalcoatl,再次感谢您。您的回答很有帮助,我感谢您所做的工作。您和黛西指出的是,我根本不了解服务容器和依赖注入的使用。这是一个事实,我将努力对该主题以及它如何在其他项目类型中实施进行更多研究。比你花时间。
猜你喜欢
  • 1970-01-01
  • 2013-01-16
  • 1970-01-01
  • 2012-01-21
  • 1970-01-01
  • 2021-04-13
  • 1970-01-01
  • 2010-12-13
  • 1970-01-01
相关资源
最近更新 更多