gpt4 book ai didi

c# - 避免对具有可为空类型/字段的泛型发出警告的最佳方法?

转载 作者:行者123 更新时间:2023-12-03 22:01:56 24 4
gpt4 key购买 nike

考虑以下人为的类:

public sealed class Test<T>
{
public void SetItem(T item)
{
_item = item;
}

public T GetItem()
{
return _item;
}

T _item; // warning CS8618: Non-nullable field '_item' is uninitialized.
} // Consider declaring the field as nullable.

假设它必须使用以下代码:
var test1 = new Test<int>();
test1.SetItem(1);
Console.WriteLine(test1.GetItem());

var test2 = new Test<string>();
test2.SetItem("One");
Console.WriteLine(test2.GetItem());

进一步假设 nullable编译时启用。

这个实现会产生一个编译器警告(如果像我们一样,你启用了“作为错误的警告”,它就会变成一个错误):

warning CS8618: Non-nullable field '_item' is uninitialized. Consider declaring the field as nullable.



我的问题很简单:

避免此警告的最佳方法是什么?

我尝试过的事情:

1) 将 _item 声明为可空:
T? _item; // Error: A nullable type parameter must be known to be a value type or non-nullable reference type

2)将类声明为:
public sealed class Test<T> where T: struct

这避免了警告,但现在行 var test2 = new Test<string>();不会编译

3)将类声明为:
public sealed class Test<T> where T: class
...
T? _item;

这也避免了警告,但现在行 var test1 = new Test<int>();不会编译。

所以我目前所拥有的是:
public sealed class Test<T>
{
public void SetItem(T item)
{
_item = item;
}

public T GetItem()
{
return _item;
}

#pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
T _item;
#pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
}

这真的是我最好的选择吗?

注意:我见过 this related question ,但它没有回答我的问题,因为答案说使用 where T : struct ,这 - 如上所述 - 不能解决问题。

[收到正确答案后编辑]

所以事实证明,对于泛型类型,没有办法使用 nullable 来表达“如果 T 是一个可以为 null 的类型,那么它可以为 null”的情况。

但是,Resharper 确实允许您这样做,因此我将两者结合使用。

当使用 Resharper 支持以及可空时,该类看起来像这样:
public sealed class Test<T>
{
public void SetItem([CanBeNull] T item)
{
_item = item;
}

[CanBeNull] public T GetItem()
{
return _item;
}

[CanBeNull] T _item = default!;
}

现在当我写这样的代码时:
var test = new Test<string>();
Console.WriteLine(test.GetItem().Length); // Warning: Possible null reference exception.

Resharper 警告我 test.GetItem()可能返回空值 - 即使编译器没有。

(遗憾的是,C# 编译器没有让我这样做,但至少我们有 Resharper!)

[进一步考虑后编辑]

如果我只是像这样使用这个类:
public sealed class Test<T>
{
public void SetItem(T item)
{
_item = item;
}

public T GetItem()
{
return _item;
}

T _item = default!;
}

然后,实例化代码有责任在需要时提供正确的可空类型 T,如下所示:
var test = new Test<string?>();

现在,如果您尝试取消引用可能为空的引用,编译器本身会警告您:
var test = new Test<string?>(); // Note "string?"
Console.WriteLine(test.GetItem().Length); // Warning about test.GetItem() possibly null.

这绝对比我在第二次编辑中所做的使用 Resharper 注释更可取,因为这实际上是错误的,因为这意味着您不能说这些值不为空。

[希望最终澄清编辑]

实际类不允许 _item除非明确设置,否则将被访问,因此更像是这样:
public sealed class Test<T>
{
public void SetItem(T item)
{
_wasSet = true;
_item = item;
}

public T GetItem()
{
if (!_wasSet)
throw new InvalidOperationException("No item set.");

return _item;
}

T _item = default!;

bool _wasSet;
}

由于使用真实类的方式,在实例化对象时,要设置的项不可用,因此无法在构造函数中设置默认值。

(真正的类是某人编写的用于提供队列的东西,您可以在其中访问队列中的第一个和第二个项目而无需将它们出队,而 _item 实际上是用于队列前端的单独值,其中队列的其余部分存储在 Queue<T> 中。这不是我做的方式,真的,但这就是我正在使用的......)

最佳答案

作为一种可能的选择,您可以使用 default 的组合文字和 null-forgiving 运营商,比如

private T _item = default!;

关于c# - 避免对具有可为空类型/字段的泛型发出警告的最佳方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59212963/

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