为什么在 C# 10 中我在初始化属性上得到一个编译器 warning/error CS8618

Why in C# 10 do I get a compiler warning/error CS8618 on init properties

我有这个代码

#enable nullable
public class SomeClass
{
  public string SomeProperty { get; init; }
}

出现以下编译器错误:

[CS8618] Non-nullable property 'SomeProperty' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

我认为将 属性 声明为 init 的全部意义在于确保在创建时使用 属性 初始化语法设置属性,例如

var s = new SomeClass { SomeProperty = "some value" };

那么为什么我会收到此编译器警告?我是否完全误解了 init 的用途?

编辑 1:

我不是唯一被这个绊倒的人。有一个Roslyn issue几乎是一样的东西。

还有一个关于required properties where Richiban asks的提议:

What's the reasoning being init props being non-mandatory? I may have missed something, but I imagine that they'll be very rarely used without a req modifier.

'can initialize'和'must initialize'有区别,init关键字没有表达清楚。由于围绕不可空引用类型和正确代码的所有模糊,我错误地认为 init 意味着 'must initialize'.

仅初始化 属性 不 要求 在创建时使用 属性 初始化语法设置属性。它允许以这种方式设置它们,而不是要求所有只读属性都由构造函数设置。

所以用你的代码,

var s = new SomeClass();

... 仍然完全有效,并且最终 s.SomeProperty 为空,与其类型的可空性相反。

使用 init 关键字 属性 值只能在构造函数或初始化块中更改。

如果你使用默认构造函数

var s = new SomeClass ();
s.SomeProperty = "A value";//Compiler error CS8852  Init-only property or indexer "SomeClass.SomeProperty" can only be assigned in an object initializer, or on "this" or "base" in an instance constructor or an "init" accessor.

属性SomeProperty 已用 null 初始化,但不可为 null 引用类型。编译器正在报告未来可能出现的运行时错误。 警告 CS8618不可为空 属性“SomeProperty”在退出构造函数时必须包含非空值。考虑将 属性 声明为可为 null。

如果没有发生这种情况,可以通过以下方式删除警告

1.使用 null forgiving operator

public class SomeClass
{
    public string SomeProperty { get; init; } = null!;// indicating null value is a correct not null value. 
}

当您尝试访问和使用 SomeProperty 值时,您需要检查可空性以避免空引用异常,即使该类型表明它不可为空。真气人。

if(s.SomeProperty==null) //OK
{
   //DO SOME STUFF
}

var length = s.SomeProperty?.Length ?? 0; //OK

var length2 = s.SomeProperty;//NullReferenceException

2。 Assigning/Initialize 属性

的有效值
public class SomeClass
{
    public string SomeProperty { get; init; } = "My initial value"; 
}

您可以在不初始化 属性
的情况下调用默认构造函数 var s = new SomeClass (); //Some property is "My initial value"

或使用初始化块调用构造函数

var s = new SomeClass()
{
   SomeProperty = "My new intial value"
};


var length = s.SomeProperty.Length; //NO exception / No problem

3。创建带参数的构造函数,避免使用默认构造函数

Errors/Warnings只出现在来电号码中

public class SomeClass
{
    public string SomeProperty { get; init; } //ALL OK. CS8618 dissapeared / No Warning.

    public SomeClass(string someProperty)
    {
        SomeProperty = someProperty;
    }
}

var s = new SomeClass(); //CS7036 ERROR.


var s2 = new SomeClass() //CS7036 ERROR.
{
    SomeProperty = "My new intial value"
};

var s3 = new SomeClass("My new initial value"); //OK. No Warning

var s4 = new SomeClass("My new initial value") //OK. No Warning.
{
    SomeProperty = "My other new intial value"
};

s4.SomeProperty = "A value"; //CS8852 ERROR. SomeProperty is enabled to only be initialized in constructor or intialize block.