【问题标题】:Why does C# not warning about non-nullable long field?为什么 C# 不对不可为空的长字段发出警告?
【发布时间】:2021-09-15 09:35:14
【问题描述】:

为什么我没有在构造函数中设置 FieldTwo 时没有收到不可为空的警告(或其他警告)?我正在使用 .Net 5.0 并且在项目文件中将 Nullable 选项设置为 true。

  public class MyClass
  {
    public string FieldOne;
    public long FieldTwo;

    public MyClass (string p1, long p2)
    {
      FieldOne = p1;
      // FieldTwo is not set. Where is the non-nullable warning!?
    }
  }

【问题讨论】:

  • 谢谢。无论如何,这里有编译器警告吗?我不希望它默认为0,我希望编译器强制我从构造函数中的参数设置值
  • long 是一个值类型,它永远不能为空。您没有可空性警告。这些是字段,而不是属性,长类型字段的值为 0。您必须使用 long 吗?能够存储空值。这将生成一个Nullable<long> 字段,它可以接受空值
  • 所以编译器实际上没有办法告诉程序员他们犯了一个错误,他们忘记在构造函数中显式设置 PropertyTwo 字段?
  • 由于long 不可为空,因此适用于值类型的通常规则:如果您在构造函数中不做任何事情,它会使用default 进行初始化,这意味着它以0 结束。这个决定(以及不需要显式初始化,甚至警告它的决定)一直追溯到 C# 的第一个版本,并且与可空性问题正交(应用程序在访问具有值 @ 的 long 时不会崩溃987654330@,毕竟,虽然它可能会出现故障)。
  • @cdimitroulas 这里真正的错误是调用字段Property。字段是实现细节。是的,有一些方法可以要求所有属性中的值,例如使用Required 属性,或者在C# 8 及更高版本中,使用record。你想做什么?

标签: c# .net


【解决方案1】:

long 是值类型,不能为空。所以没有理由警告null。我怀疑你想要的是一个字段未初始化警告。

如果从未分配私有字段,则会导致 CS0649 警告。但是,如果字段 public 或在类中的任何位置被修改,则不会引发此警告。例如,下面是完全可以接受的代码,并且不应该给出警告:

public class MyClass{
    private long myLong;
    public void Increment() => myLong++;
}

如果该字段只能从构造函数中设置,则应将其声明为只读。但是,公共只读字段不会触发警告,即使它们可能应该触发。见Why do I NOT get warnings about uninitialized readonly fields?

【讨论】:

  • 请注意,如果您将属性声明为 get-only,则编译器会在未分配时警告您:public long PropertyTwo { get; }
  • @MatthewWatson Really?
  • 哦,一定是 Resharper 警告。编辑:是的,我刚刚检查过。 Resharper 警告你。如果您不指定 readonly long,Resharper 也会警告您。
  • 如果您使用只读字段,内置代码分析也会警告您:Warning CS0649 Field 'MyClass._propertyTwo' is never assigned to, and will always have its default value 0 - 所以也有这种可能性。
  • @Matthew Watson,我更新了答案。看起来私有字段会引发警告,无论是否只读,但公共字段不会,即使公共字段是只读的。至少在 .net 4.8 中。
【解决方案2】:

long 是值类型,不能为空。值类型总是在使用默认值声明时进行初始化,在本例中为 0。如果您想存储 null,则必须将 field 类型更改为 long?

这些字段无论如何都不是属性。这不仅仅是语义。字段是实现细节,甚至是公共字段。它们不被视为类 API 表面的一部分。属性 API 的一部分,默认情况下它们会被所有序列化程序序列化(字段不会)并保证事实上拥有公共字段是一种代码味道。

为确保所有属性都已初始化,您可以使用record 类型而不是class

public record(string PropertyOne, long PropertyTwo);

这将为PropertyOnePropertyTwo 生成一个仅具有初始化属性的类,以及一个需要所有属性值的构造函数。以及相等运算符、解构器和ToString() 实现,它以 JSON 字符串的形式返回所有属性。

【讨论】:

  • “公共字段”在 C# 中甚至是允许的事情,这让我有点困惑...
猜你喜欢
  • 2021-12-27
  • 2018-07-18
  • 1970-01-01
  • 2020-05-03
  • 1970-01-01
  • 2011-01-28
  • 2013-06-19
  • 1970-01-01
相关资源
最近更新 更多