gpt4 book ai didi

C# 8.0 不可为空的引用类型和选项模式

转载 作者:行者123 更新时间:2023-12-03 17:00:35 25 4
gpt4 key购买 nike

Tl;博士:我想要一个对其成员使用不可为空类型且没有默认值的选项类。

C# 8.0 引入 Nullable Reference Types.

我发现在 ASP.Net Options Pattern 中使用可为空的引用类型相当困难,不完整,或者我错过了一些东西。我遇到了此 stack over flow post 中描述的相同问题.

  1. We don't want to make Name nullable as then we need to place traditional null checks everywhere (which is against the purpose of non-nullable reference types)
  2. We can't create a constructor to enforce the MyOptions class to be created with a non-nullable name value as the Configure method construct the options instance for us
  3. We can't use the null-forgiving operator trick (public string name { get; set; } = null!;) as then we can't ensure the Name property is set and we can end up with a null in the Name property where this would not be expected (inside the services)


我想要一个对其成员使用不可为空类型且没有默认值的选项类。 无论如何,该帖子中的答案最终都使用可空类型(我试图避免)或默认值(我也试图避免)。

关于 options validation 的评论提出好的观点,看起来很有希望,但事实证明 Validate方法仍然需要一个选项对象来验证,如果您已经必须将选项对象传递给它,这将违背目的。
public ValidateOptionsResult Validate(string name, MyOptions options)
// Pointless if MyOptions options is being passed in here

这是没有意义的,因为我已经确定强制使用所有不可为空的成员且没有默认值的选项类的唯一方法是拥有一个构造函数。以下面的代码示例为例。

namespace SenderServer.Options
{
using System;
using Microsoft.Extensions.Configuration;

/// <summary>
/// Configuration options for json web tokens.
/// </summary>
public class JwtOptions
{
/// <summary>
/// The secret used for signing the tokens.
/// </summary>
public String Secret { get; }

/// <summary>
/// The length of time in minutes tokens should last for.
/// </summary>
public Int32 TokenExpirationInMinutes { get; }

/// <summary>
/// Configuration options for json web tokens.
/// </summary>
/// <param name="secret"> The secret used for signing the tokens.</param>
/// <param name="tokenExpirationInMinutes">The length of time in minutes tokens should last for.</param>
public JwtOptions(String secret, Int32 tokenExpirationInMinutes)
{
Secret = secret;
TokenExpirationInMinutes = tokenExpirationInMinutes;
}

/// <summary>
/// Create a JwtOptions instance from a configuration section.
/// </summary>
/// <param name="jwtConfiguration">The configuration section.</param>
/// <returns>A validated JwtOptions instance.</returns>
public static JwtOptions FromConfiguration(IConfiguration jwtConfiguration)
{
// Validate the secret
String? secret = jwtConfiguration[nameof(Secret)];
if (secret == null)
{
throw new ArgumentNullException(nameof(Secret));
}

// Validate the expiration length
if (!Int32.TryParse(jwtConfiguration[nameof(TokenExpirationInMinutes)], out Int32 tokenExpirationInMinutes))
{
throw new ArgumentNullException(nameof(TokenExpirationInMinutes));
}

if (tokenExpirationInMinutes < 0)
{
throw new ArgumentOutOfRangeException(nameof(TokenExpirationInMinutes));
}

return new JwtOptions(secret, tokenExpirationInMinutes);
}
}
}

因此,如果我需要一个带有类参数的构造函数,那么我可以自己实例化它,例如:

// Configure the JWT options
IConfiguration jwtConfiguration = Configuration.GetSection("Authentication:JwtOptions");
JwtOptions jwtOptions = JwtOptions.FromConfiguration(jwtConfiguration); // This performs validation as well

但是我应该把 jwtOptions 放在哪里? ?没有 services.Configure<JwtOptions>(jwtOptions);和变体只接受一个已经实例化的对象(或者至少没有我见过的)。最后,即使他们这样做了,您也不能使用没有公共(public)无参数构造函数的依赖注入(inject)选项类。

public JwtService(IOptions<JwtOptions> jwtOptions)

最佳答案

I want an options class that uses non-nullable types for its members with no defaults.


不幸的是,Microsoft.Extensions.Options 根本不适合您。 Options 的工作方式是拥有一个由多个源、操作和验证器组成的配置管道,它们都使用相同的选项对象。由于该管道没有明确的开始,并且任何配置源都可以位于管道中的任何位置,因此选项对象的构造由框架处理,并且在调用任何配置源之前进行。
这对于 Options 允许它具有的不同类型的用例是绝对必要的:您可以从配置 (Microsoft.Extensions.Configuration) 配置选项,您可以通过配置操作配置它们,您可以通过具有附加功能的服务来配置它们依赖项等。所有这些都可以按任何顺序运行。
因此,由于对象的构造是由框架进行的,因此还需要使用默认值来创建选项对象:通常,这些只是类型的 default值,但您也可以通过对象的构造函数选择不同的默认值。
如果您想强制在管道之后配置特定参数,您可以使用配置后操作来强制配置,或使用选项验证来验证配置的选项。但是由于这一切都在管道中运行,因此您需要有默认值。
所以基本上,如果你需要有没有默认值的不可为空的属性,那么你不能使用选项。至少不是开箱即用。如果你想这样做是为了安全地引用你的服务中的选项,那么会有一种不同的方法来解决这个问题:而不是注入(inject) IOptions<T> , 注入(inject)一个不可为空的选项对象 T直接地。并通过工厂提供:
services.AddSingleton<MySafeOptions>(sp =>
{
var options = sp.GetService<IOptions<MyUnsafeOptions>>();
return new MySafeOptions(options.Value);
});
services.Configure<MyUnsafeOptions>(Configuration.GetSection("MyOptions"));

关于C# 8.0 不可为空的引用类型和选项模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61420984/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com