C#可空特性下如何避免重复检查AccessToken空引用?
问题:避免空引用检查重复或抑制警告
场景
我有一段获取访问令牌的代码:
private async Task<TokenResponse> GetTokenResponse(Credentials credentials, CancellationToken cancellationToken, string? scope = null) { var tokenResponse = await _httpClient.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest { RequestUri = new Uri("url that works", UriKind.Relative), ClientId = credentials.ClientId!, ClientSecret = credentials.ClientSecret, Scope = scope }, cancellationToken); if (tokenResponse.IsError || string.IsNullOrEmpty(tokenResponse.AccessToken)) { throw new AuthenticationException($"Error fetching token: {tokenResponse.Error}"); } return tokenResponse; }
我需要通过两种方式调用该方法:
方式1
public async Task<string> GetAccessTokenAsync(Credentials credentials, CancellationToken cancellationToken) { var tokenResponse = await GetTokenResponse(credentials, cancellationToken); return tokenResponse.AccessToken; }
此方式会提示可能的空引用,因为tokenResponse.AccessToken可为null。
方式2
public async Task<TokenResponse> GetAccessTokenWithScope(Credentials credentials, string scope, CancellationToken cancellationToken) { var tokenResponse = await GetTokenResponse(credentials, cancellationToken, scope); return tokenResponse; }
我需要这种方式,因为后续需要TokenResponse的其他属性,包括AccessToken。
问题
在这两种调用方式中,尽管我已在GetTokenResponse方法中确认AccessToken不为null,但仍需重复检查空引用。由于TokenResponse不是自定义类无法设置必填字段,请问如何避免重复检查或使用!运算符抑制警告?
解决方案
1. 直接使用空值抑制运算符!
既然GetTokenResponse已经通过异常确保返回的TokenResponse中AccessToken非空,直接用!运算符明确告知编译器此处不会为空,是最简洁的解决方案:
修改方式1的代码:
public async Task<string> GetAccessTokenAsync(Credentials credentials, CancellationToken cancellationToken) { var tokenResponse = await GetTokenResponse(credentials, cancellationToken); return tokenResponse.AccessToken!; }
对于方式2,后续使用AccessToken时直接添加!即可:
var token = await GetAccessTokenWithScope(creds, "scope", ct); var accessToken = token.AccessToken!;
2. 封装扩展方法统一处理
如果不想在代码中到处写!,可以给TokenResponse编写扩展方法,封装非空验证逻辑(即使底层已经检查,也能在后续逻辑变更时提供额外保障):
public static class TokenResponseExtensions { public static string GetSafeAccessToken(this TokenResponse tokenResponse) { return tokenResponse.AccessToken ?? throw new InvalidOperationException("AccessToken cannot be null after successful token retrieval"); } }
调用示例:
// 方式1修改后 public async Task<string> GetAccessTokenAsync(Credentials credentials, CancellationToken cancellationToken) { var tokenResponse = await GetTokenResponse(credentials, cancellationToken); return tokenResponse.GetSafeAccessToken(); } // 方式2后续使用时 var token = await GetAccessTokenWithScope(creds, "scope", ct); var accessToken = token.GetSafeAccessToken();
3. 使用Debug断言辅助编译器推断
通过Debug.Assert可以在Debug模式下验证AccessToken非空,同时让编译器自动推断该属性不为空,消除警告:
using System.Diagnostics; public async Task<string> GetAccessTokenAsync(Credentials credentials, CancellationToken cancellationToken) { var tokenResponse = await GetTokenResponse(credentials, cancellationToken); Debug.Assert(tokenResponse.AccessToken != null, "AccessToken should not be null after GetTokenResponse"); return tokenResponse.AccessToken; }
Debug.Assert仅在Debug模式下执行检查,Release模式会被移除,不会影响性能。
内容的提问来源于stack exchange,提问作者Sirvis
相关产品推荐
相关产品推荐

