我正在使用新的C#8可空引用类型功能,并在重构我的代码时,我遇到了这个(简化)方法:
public T Get<T>(string key)
{
var wrapper = cacheService.Get(key);
return wrapper.HasValue ? Deserialize<T>(wrapper) : default;
}
Run Code Online (Sandbox Code Playgroud)
现在,这给出了一个Possible null reference return逻辑上的警告,因为default(T)将为所有引用类型赋予null.起初我以为我会把它改成以下内容:
public T? Get<T>(string key)
但这不可能做到.它说我要么必须添加通用约束where T : class或where T : struct.但是,这是不是一种选择,因为这既可以是(我可以存储int或int?或实例FooBar在缓存或其他).我还读到了一个假定的新泛型约束,where class?但似乎没有用.
我能想到的唯一简单的解决方案是使用null forgiving运算符更改return语句:
return wrapper.HasValue ? Deserialize<T>(wrapper) : default!;
Run Code Online (Sandbox Code Playgroud)
但这感觉不对,因为它肯定是空的,所以我基本上对这里的编译器撒谎:-)
我怎样才能解决这个问题?我错过了一些完全明显的东西吗?
在HNQ 上阅读了这个问题后,我继续阅读C# 8 中的可空引用类型,并做了一些实验。
我非常清楚,当有人说“我发现了一个编译器错误!”时,10 次中有 9 次,甚至更频繁。这其实是有意为之,也是自己的误会。而且因为我今天才开始研究这个功能,显然我对它不是很了解。有了这个,让我们看看这段代码:
#nullable enable
class Program
{
static void Main()
{
var s = "";
var b = s == null; // If you comment this line out, the warning on the line below disappears
var i = s.Length; // warning CS8602: Dereference of a possibly null reference
}
}
Run Code Online (Sandbox Code Playgroud)
在阅读我上面链接的文档后,我希望该s == null行给我一个警告——毕竟s显然是不可为空的,所以将它与它进行比较null是没有意义的。
相反,我在下一行收到警告,警告说这s可能是一个空引用,即使对于人类来说,很明显它不是。
此外,如果我们不与 进行比较,则不会显示警告。 …
我有以下课程:
public class KeyDTO<T>
{
public T Id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
到目前为止一切顺利,但我希望类型参数T是一个非可空类型.我在某处读过这可能是可行的:
public class KeyDTO<T> where T : IComparable, IComparable<T>
{
public T Id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我public T Id改为public T? Id,我会收到编译错误,告诉我T必须是不可为空的.
如何指定泛型类型参数必须是非可空的?
我想完成这个,因为我想Id用[Required]属性注释我的属性,如下所示:
public class KeyDTO<T> {
[Required]
public T Id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
什么[Required]是验证模型,因此T不能为空.
但是,如果我有KeyDTO<int>,Id将被初始化为0,绕过我的[Required]属性
考虑以下(VS 16.8.0 Preview 2.1 C# 9.0 preview)代码:
#nullable enable
using System.Collections.Generic;
class Archive<T> where T : notnull
{
readonly Dictionary<string, T> Dict = new();
public T? GetAt(string key)
{
return Dict.TryGetValue(key, out var value) ? value : default;
}
}
class Manager
{
public int Age { get; set; }
}
class Main34
{
long F3()
{
Archive<long> a = new();
var johnAge = a.GetAt("john");
if (johnAge is null) return -1; // Error CS0037 Cannot convert null to 'long' because …Run Code Online (Sandbox Code Playgroud)