我可以使用 C# 9 记录作为 IOptions 吗?

Nik*_*sen 13 c# record c#-9.0

我刚刚开始使用 C# 9 和 .NET 5.0,特别是新record结构。我发现我有很多关于记录类型速记语法的优秀用例。

我考虑过的用例之一是对 ASP.NET Core 应用程序使用recorddto in IOptions<>,而不是常规类。这些选项类通常很简单,所以我认为它非常适合,但似乎我不能让它轻松工作,因为使用配置应用程序IOptions<>需要对象具有无参数构造函数。

public record MyOptions(string OptionA, int OptionB);

public class Startup
{
    public void ConfigureServices(IServiceCollection services) {
        services.Configure<MyOptions>(Configuration.GetSection(nameof(MyOptions)));
    }
...
}

public class MyController : Controller 
{
    private readonly MyOptions _options;
    public MyController(IOptions<MyOptions> options) {
        _options = options.Value;  // This throws an exception at runtime
    }
}

Run Code Online (Sandbox Code Playgroud)

上面的示例在尝试访问该IOption<>.Value属性时抛出以下异常:

System.MissingMethodException: '没有为类型 'AcmeSolution.MyOptions' 定义无参数构造函数。

有没有办法配置IOptions配置系统以使用记录的构造函数反序列化选项,而不是需要无参数的构造函数?

我可以对记录使用普通语法,但是使用类确实没有任何好处。

Bra*_*ano 15

C#10

我知道这个问题专门引用了 C# 9,但如果您生活在当下(我怀疑你们大多数人都是这样),那么这在 C# 10 (ASP.NET Core 6) 中可以按预期工作:

public record MyOptions
{
  public string MyProperty { get; init; }
}

// ...

builder.Services.Configure<MyOptions>(builder.Configuration);

Run Code Online (Sandbox Code Playgroud)

  • 它确实有效。我只是想知道这是否在某个地方有记录,因为我找不到任何提及它的可能性的内容。可能它只是“偶然”工作,因为“init”设置器的编译方式与“正常”设置器类似,只是带有一些[附加元数据](https://sharplab.io/#v2:C4LglgNgNAJiDUAfAsAKAG4EMBOACA9rgLy4B2ApgO64DyADsGPqQM64Deau3uAgnWACq2CMVwAiAK4jxULj35gA0uQCeY8QGs1 snrjQBfANxp8AOkXCIJKSICM4k6gD0z84pXqb21QCZHaGgAAgDMuEG+tAxMrGicqHqh4XYADHwCVhy4AObkwEa4LHkFBhoBCTxJQanpympZufm4YKRgTaU25QZAA=) 用于编译器防止设置施工后的它。我想这很好...... (2认同)

Bli*_*ndy 11

有没有办法配置 IOptions 配置系统以使用记录的构造函数反序列化选项,而不是需要无参数构造函数?

不,通常 ASP.Net Core 使用大量运行时类型实例化,这需要事先知道的构造函数调用,在这种情况下,它需要一个没有参数的构造函数。

但是,您可以使您的记录类具有无参数构造函数:

public record MyOptions(string OptionA, int OptionB)
{
    public MyOptions(): this(default, default) {}
}
Run Code Online (Sandbox Code Playgroud)

这值得么?诶。由你决定。在性能方面,它并不比普通课程差,所以选择任何你觉得更清晰的课程!

编辑:或者,您应该可以使用此表单:

public record MyOptions(string OptionA = default, int OptionB = default);
Run Code Online (Sandbox Code Playgroud)

  • “public record MyOptions(string OptionA = default, int OptionB = default);”似乎不起作用。 (3认同)