对我来说,将 null 作为参数传递给Task.FromResult
.
不,这是个坏主意。
如果调用者为 then 指定了不可为空的类型,T
则default(T)
可以将其视为“未定义”(实际上是null
,但这是 C# 8.0 实现不可空引用类型的主要缺点(即它们仍然可以是,null
grrrr)。考虑:
// Compiled with C# 8.0's non-nullable reference-types enabled.
Task<String> task = GetDefaultTask<String>();
String result = await task;
Console.WriteLine( result.Length ); // <-- NullReferenceException at runtime even though the C# compiler reported `result` cannot be null.
避免在 C# 8.0 中对没有足够类型约束的泛型类型使用default
/ 。default(T)
这个问题有几个解决方案:
1:指定调用者提供的默认值:
public Task<T> GetDefaultTask<T>( T defaultValue )
{
return Task.FromResult( defaultValue );
}
因此调用站点需要更新,如果调用者null
在运行时尝试使用而不是异常,C# 编译器将给出警告或错误:
Task<String> task = GetDefaultTask<String>( defaultValue: null ); // <-- compiler error or warning because `null` cannot be used here.
String result = await task;
Console.WriteLine( result.Length );
2:在不同的方法上添加结构与类约束:
/value-type的可能是有意义default(T)
的struct
(或者它可能和null
... 一样危险),因为我们可以安全地使用default(T)
whereT : struct
而不是default(T)
where T : class
,我们可以为这种情况添加不同的重载:
public Task<T> GetDefaultTask<T>()
where T : struct
{
return Task.FromResult( default(T) );
}
public Task<T> GetDefaultTask<T>( T defaultValue )
where T : class
{
return Task.FromResult( defaultValue );
}
(请注意,您不能仅基于泛型类型约束重载方法 - 您只能通过泛型参数计数和普通参数类型重载。