如何强制泛型方法绝不返回Null值(含异步场景)
问题场景
在以下代码示例中:
async Task Main() { // 实际上data永远不可能为null,但这里被推断为Response?类型 var data1 = GetResponseData(); var data2 = await GetResponseDataAsync(); } private Response GetResponseData() { var data = MyHelper("the method", m => GetData<Response>(m)); return data; } private Task<Response> GetResponseDataAsync() { var data = MyHelperAsync("the method", m => GetDataAsync<Response>(m)); // 这里会触发可空性警告 return data; } class Response { public int prop { get; set; } } TResp? GetData<TResp>(string method) { return default(TResp); } TResp MyHelper<TResp>(string method, Func<string, TResp> getData) { var data = getData(method); if (data is null) throw new Exception("data should not be null"); return data; }
Main方法中的data变量被编译器标记为可空类型(Response?),但实际上它永远不会为null。需要让编译器识别这一事实,且不能修改可能返回null的GetData方法。
解决方案
同步场景修正
给MyHelper方法添加[return: System.Diagnostics.CodeAnalysis.NotNull]特性,明确告知编译器该方法返回值绝不会为null,无需修改GetData方法:
using System.Diagnostics.CodeAnalysis; // 其余代码保持不变 [return: NotNull] TResp MyHelper<TResp>(string method, Func<string, TResp> getData) { var data = getData(method); if (data is null) throw new Exception("data should not be null"); return data; }
添加该特性后,编译器会正确推断GetResponseData()的返回值为非空Response,Main中的data1也会被识别为非空类型,不再出现错误的可空标记。
异步场景解决方案
该方案同样适配异步场景,只需给异步版的MyHelperAsync添加[return: NotNull]特性即可:
async Task Main() { var data2 = await MyHelperAsync("the method", m => GetDataAsync<Response>(m)); data2.prop.Dump(); } class Response { public int prop { get; set; } } Task<TResp?> GetDataAsync<TResp>(string method) { return Task.FromResult(default(TResp)); } using System.Diagnostics.CodeAnalysis; [return: NotNull] async Task<TResp> MyHelperAsync<TResp>(string method, Func<string, Task<TResp>> getData) { var data = await getData(method); if (data is null) throw new Exception("data should not be null"); return data; }
添加特性后,MyHelperAsync的返回值会被编译器识别为非空的Task<Response>,异步场景下的可空性警告会自动消失。
内容的提问来源于stack exchange,提问作者fpdave100
相关产品推荐
相关产品推荐

