C# 当参数类型为动作<;SomeObject>;

C# 当参数类型为动作<;SomeObject>;,c#,asp.net-core,C#,Asp.net Core,我在查看github上的.net core 2.0代码,以便在一篇文章中解开一些代码,我发现: publicstaticimvcbuilderaddrazorpagesoptions( 这个IMvcBuilder, 行动(行动) { } 经过审查,似乎从未显式实例化过RazorPagesOptions类型的对象。我当时的问题是RazorPageOptions类型的对象是如何实例化的?这与依赖注入模式的ASP.NET核心实现有关。Daisy在评论中指出的正是: builder.Services.

我在查看github上的.net core 2.0代码,以便在一篇文章中解开一些代码,我发现:

publicstaticimvcbuilderaddrazorpagesoptions(
这个IMvcBuilder,
行动(行动)
{ }

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

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

builder.Services.Configure(setupAction)
builder
IMvcBuilder
builder.Services
IServiceCollection
,也就是说,设置为在asp net应用程序中可用的所有服务的主列表。在Startup.cs中安装了FoobarService?然后IFoobarService的定义将可能位于servicecolection中。等等

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

然后,除了服务注册和建立工厂之外,因为“每个人都习惯”在Startup.cs中设置东西,其中ServiceCollection是焦点,此外,还可以通过ServiceCollection或姐妹对象上的更多扩展方法在Startup.cs中自定义配置服务可能需要的更多详细信息

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

。。这和你发现的很接近。该行:

builder.Services.Configure(setupAction)
采取行动(函子,采取1个参数:剃刀选项),并登记在所有服务的大袋信息。它被注册为RazorPagesOptions的设置源。作为一个副作用,IoC容器还了解到一些服务可能需要某种东西
RazorPagesOptions

稍后,在运行时,当有人请求一个服务实例时,如果该服务需要
RazorPagesOptions
,容器将检查它是否已经准备好。如果不是,则会创建那些
RazorPagesOptions
的实例(可能在单例模式下),但它最初当然是空的。然后,它将通过所有注册的设置源传递。每个这样的源都会依次被调用,每个源都会获得RazorPagesOptions实例,每个源都有机会用自己的部分设置填充该实例。最后,当运行所有这些时,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=>{..}
是将传递到AddRazorPagesOptions,然后传递到
serviceCollection的
操作。配置
,并将其注册为RazorPagesOptions的实际设置源

外卖:

  • 假设您编写了一个ASP.NET Core MVC应用程序,则是您在Startup.cs中的代码创建了Action delegate实例,或者在调用AddRazorPagesOptions方法时编写lambda时实际上是“编译器完成了”
  • 此委托(可能)不会立即调用,但会存储起来供以后使用
  • 在应用程序的运行时生命周期中的某个时间,ASP.NET核心MVC框架将注意到需要RazorPagesOptions,并将创建实例。可能是通过反射或Activator.CreateInstance(类型),这样您就不会在任何地方找到新的RazorPagesOptions()
  • 所有这些都是ASP.NET核心MVC特有的,而不是纯C#
  • 类似的机制和模式存在于其他库/框架/IOCC/etc中
  • 最后一点——我试着用“容易理解的方式”来写,而不是100%准确。我在这里写的很多东西都是“有点不真实”,但我知道,已经足够接近了

该代码只是将操作传递给
builder.Services.Configure(setupAction)
,因此可能会创建选项或将其传递给其他执行操作的对象。(但从根本上说,您需要根据您的标题确定您的问题是否是一般性的,或者您是否对Razor/ASP.NET关于
RazorPagesOptions
的核心特定问题感兴趣)这是一个一般性的问题。从我所知道的来看,对象正在为我实例化。我在一个控制台应用程序中运行了一个单独的测试,尝试了这种方法,没有创建对象的实例,并且使用了一个非静态方法,它工作得很好。一些关于如何使用这种方法为我创建对象的实例的问题。问题是自动获取对象的实例当我将其用作参数的一部分时,该参数是没有返回类型的委托否,没有任何东西会自动创建实例。如果您将其编辑为包含您的控制台应用程序,其中包含您不了解的方面的详细信息,并删除剃须刀,则这听起来是一个更容易回答的问题页
services
    .AddMvc()  // registers MVC services in IoCC and gets you the IMvcBuilder
    .AddRazorPagesOptions(options => 
{
    options.RootDirectory = "....";
    options.Conventions.Add(new FooConvention....);
    ...
});