【问题标题】:What is difference between Init-Only and ReadOnly in C# 9?C# 9 中的 Init-Only 和 ReadOnly 有什么区别?
【发布时间】:2020-06-14 12:19:14
【问题描述】:

我正在处理即将发布的C# 9 new features。正在引入Init-Only 属性。

今天的一大限制是属性必须是可变的,对象初始化器才能工作:它们通过首先调用对象的构造函数(在本例中为默认的无参数构造函数)然后分配给属性设置器来发挥作用。

仅初始化属性解决了这个问题!他们引入了一个 init 访问器,它是 set 访问器的一个变体,只能在对象初始化期间调用:

public class Person
{
    public string FirstName { get; init; }
    public string LastName { get; init; }
}

有了这个声明,上面的客户端代码仍然是合法的,但是任何后续对 FirstName 和 LastName 属性的赋值都是错误的。这行是什么意思?如果 ReadOnly 也做同样的事情,那么 Init-Only 属性的用途是什么。

【问题讨论】:

  • “即将发布” - 你从哪里得到这个想法?到目前为止,即使是实验性的,也没有实现或可用。他们说它主要只适用于 .NET 5.0 及更高版本,但这并不意味着它会在同一时间范围内发布。事实上,从逻辑上讲,他们可以在 2040 年发布它,“它需要 .east .NET 5.0”。据我所知,没有任何迹象表明我们何时可以使用这些特征,即使是在实验水平上也是如此。
  • @Supergibbs 完全没问题,这确实是一个很好的实用问题。但是有些人擅长拉别人的腿。

标签: c# c#-9.0


【解决方案1】:

正如新的 C# 9 features post, 中所述

今天的一大限制是属性必须是可变的 使对象初始化器工作:它们通过首先调用 对象的构造函数(在这种情况下是默认的无参数构造函数)和 然后分配给属性设置器。

但是,带有 readonly 修饰符的值类型是不可变的,如 readonly documentation 中所述。

因此,无法将只读属性与对象初始化器一起使用。

但是,对于仅 Init 属性,您可以使用对象初始值设定项。

【讨论】:

  • 谢谢,除了这个不同之外,两者在各个方面都相同吗?或者换句话说,我可以说使用对象初始化器来读取他们提出的 Init_Only 属性的属性吗?
  • 我认为这是实现这个新功能的主要原因,但没有更多关于实现细节的信息,我不确定。
  • 你能举个例子说明两者的区别
  • @viveknuna 去看看mybuild.microsoft.com/sessions/…
  • 通过 init,调用者可以使用属性初始化语法来设置值,同时仍然保持不变性(只读属性)。
【解决方案2】:

Init-only 属性的目的是只允许在对象初始化器或类的构造器中进行赋值。

如果我们考虑您的 Person 类,则允许在构造函数或对象初始化程序中分配给 FirstNameLastName,但您不能在其他地方分配给 FirstNameLastName

public class Person
{
    public string FirstName { get; init; }
    public string LastName { get; init; }

    // this is a constructor
    public Person()
    {
        this.FirstName = "first name"; // works
        this.LastName = "last name"; // works
    }
}

//this is a random method
public SomeMethod()
{
    Person myPerson = new Person
    {
        FirstName = "first name", // works
        LastName = "last name" // works
    };

    myPerson.FirstName = "change the first name"; // Error (CS8852)
    myPerson.LastName = "change the last name"; // Error (CS8852)
}

【讨论】:

  • 这不是一个很好的例子:if Person 的构造函数永远不会分配给 LastName,如果你这样做 Person p = new Person() { FirstName = "bob" }(并且 永远不会 分配给LastName) 然后程序无意中违反了class Person 的合同,因为LastName 现在是null,尽管输入为String(不是String?),这会抛出C# 的可空引用类型检查能力。
  • @Dai 我不明白你为什么说这不是一个很好的例子,“如果 Person 的构造函数从不分配给 LastName ......”首先这里不是这样。其次,还有第二个条件:启用可空值。如果尽管有所有这些情况,有人碰巧遇到了您描述的情况,CS8616 会让他们知道有问题
  • CS8616 仅适用于引用类型 - 如果您使用值类型或在您的 .csproj 中禁用了 #nullable,那么编译器根本不会给您任何警告。跨度>
  • 好吧,这又是一个条件(在我的示例中再次没有满足)。事实上,CS8616 不会弹出,但你会得到CS0843。如果您要禁用可空值,那么可空引用类型检查功能不存在,因此拥有 CS8616 是没有意义的。
  • CS0843 仅适用于 struct 类型,不适用于类。
【解决方案3】:

与设置不同,仅初始化属性只能在构造函数中设置或使用属性初始值设定项。

【讨论】:

  • 您的回答并没有增加多少价值。您是否有其他答案未涵盖的新内容要添加?
猜你喜欢
  • 2012-05-03
  • 2012-02-08
  • 1970-01-01
  • 1970-01-01
  • 2017-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多