【问题标题】:Automated property with getter only, can be set, why?仅带有 getter 的自动化属性,可以设置,为什么?
【发布时间】:2016-04-17 01:27:06
【问题描述】:

我创建了一个自动化属性:

public int Foo { get; } 

这只是吸气剂。 但是当我构建一个构造函数时,我可以更改值:

public MyClass(string name)
{
    Foo = 5;
}

为什么有可能,即使这是 get-only?

【问题讨论】:

  • 它实际上并没有使用setter(因为它没有)。它直接设置底层字段(对我们来说是隐藏的,这就是为什么你需要使用属性名)
  • 属性有什么用,如果它永远可以被初始化/设置? Yacoub Massad 完美地回答了这个问题

标签: c# c#-6.0


【解决方案1】:

这是一个新的 C# 6 功能,“Getter-only auto-properties”,也称为“用于只读属性的 Auto-Property Initializers”,如本 MSDN magazine article 'C# : The New and Improved C# 6.0' by Mark MichaelisC# 6.0 draft Language Specification 中所述。

只读字段的设置器只能在构造函数中访问,在所有其他情况下,该字段仍然是只读的并且行为与以前一样。

这是一种方便的语法,可以减少您需要键入的代码量,并且无需显式声明一个私有模块级变量来保存值。

这个特性被认为与 C#3 中引入自动实现的属性一样重要,可变属性(具有 getter 和 setter 的)比不可变的(只有 getter 的)编写起来更快,这意味着人们倾向于使用可变属性来避免必须为只读属性通常需要的支持字段键入代码。在relevant section of the Microsoft C# Programming Guide 中有更多关于自动实现属性的讨论。

This blog post, '#1,207 – C# 6.0 – Auto-Property Initializers for Read-Only Properties' by Sean Sexton有很好的解释和例子如下:

在 C# 6.0 之前,如果你想要一个只读(不可变)属性,你会 通常使用在 构造函数,如下所示。

public class Dog 
{
    public string Name { get; set; }

    // DogCreationTime is immutable
    private readonly DateTime creTime;
    public DateTime DogCreationTime 
    {
        get { return creTime; }
    }

    public Dog(string name)
    {
        Name = name;
        creTime = DateTime.Now;
    }
}

在 C# 6.0 中,您可以使用自动实现的属性来实现 只读属性。您可以使用自动属性来执行此操作 初始化器。结果比上面的例子干净得多,其中 我们必须明确声明一个支持字段。

public class Dog
{
    public string Name { get; set; }

    // DogCreationTime is immutable
    public DateTime DogCreationTime { get; } = DateTime.Now;

    public Dog(string name)
    {
        Name = name;
    }
}

更多详情也可以在the dotnet Roslyn repo on GitHub:

现在可以在没有设置器的情况下声明自动属性。

getter-only 自动属性的支持字段是隐式的 声明为只读(尽管这只对反射很重要 目的)。可以通过初始化器初始化 属性如上例所示。此外,只有 getter 的属性可以是 在声明类型的构造函数体中赋值,这会导致 要直接分配给基础字段的值:

这是关于更简洁地表达类型,但请注意它也 消除了 mutable 和 不可变类型:自动属性是一种简写形式,仅当 你愿意让你的类是可变的,所以诱惑 默认情况下很棒。现在,有了 getter-only 自动属性, 竞争环境已在可变和不可变之间拉平。

C# 6.0 draft Language Specification 中(注意:就微软而言,语言规范是最终版本,但它是yet to be approved as a EMCA/ISO standard,因此是“草案”):

自动实现的属性

一个自动实现的属性(或简称自动属性),是 具有仅分号访问器的非抽象非外部属性 身体。自动属性必须有一个 get 访问器,并且可以选择 有一个 set 访问器。

当一个属性被指定为一个自动实现的属性时, 隐藏的支持字段自动可用于该属性, 并且访问器被实现为读取和写入 支持领域。如果自动属性没有设置访问器,则支持 字段被认为是只读的(只读字段)。就像一个只读的 字段,也可以在正文中分配仅 getter 的自动属性 封闭类的构造函数。这样的任务分配 直接到属性的只读支持字段。

自动属性可以有一个property_initializer,它是 作为 variable_initializer 直接应用于支持字段 (变量初始化器)。

【讨论】:

  • 这是愚蠢的设计。如果设置在属性被视为只读的位置,这应该是编译时错误。
  • 对我来说奇怪的是,在使用常规属性时仍然有一个编译器错误显示CS0200 C# Property or indexer cannot be assigned to -- it is read only。 “Getter-only auto-properties”是否被认为是只读的?
【解决方案2】:

“只读自动实现的属性”

首先我想澄清一下,像

这样的属性
public string FirstName { get; }

被称为“只读自动实现的属性”

要验证这一点,您可以使用 Visual Studio 运行并检查上述代码。如果将语言版本从 C#6.0 更改为 C#5.0,则编译器将抛出以下异常 功能“只读自动实现的属性”在 C# 5 中不可用。请使用语言版本 6 或更高版本。

要更改 C# 语言版本,请访问 here

现在我来回答你的第二个问题

“这只是吸气剂。但是当我构建一个构造函数时,我可以改变值”

微软在只读的逻辑上引入了“只读自动实现的属性”。正如我们所知,关键字“readonly”在 C#1.0 中可用。我们在字段上使用“readonly”关键字作为修饰符,并且该字段可以在声明时在同一构造函数中以2种方式分配类。

同样,“只读自动实现的属性”的值可以通过两种方式赋值

方式一(申报时):

public string FirstName { get; } = "Banketeshvar";

Way2(在同一类的构造函数中)

Person()
{
 FirstName  = "Banketeshvar";
}

纯只读属性

如果您正在寻找纯粹的 Readonly 属性,那就去吧

public string FullName => "Manish Sharma";

现在您不能从构造函数中分配“FullName”属性的值。 如果您尝试这样做,它将引发以下异常

“无法将属性或索引器“Person.FullName”分配给——它是只读的”

【讨论】:

  • 请注意,FullName => "foo bar" 每次都会被评估。
【解决方案3】:

自动属性功能在 C# 3.0 版本中添加到语言中。它允许您定义一个没有任何支持字段的属性,但是您仍然需要使用构造函数将这些自动属性初始化为非默认值。 C# 6.0 引入了一个称为自动属性初始化器的新功能,它允许您在没有如下构造函数的情况下初始化这些属性:

以前,如果要创建对象,则需要构造函数 使用自动属性并将自动属性初始化为 非默认值如下:

public class MyClass
{
    public int Foo { get; }

    public Foo(int foo)
    {
        Foo = foo;
    }
}

现在在 C# 6.0 中,可以使用具有自动属性的初始化程序 意味着不需要显式的构造函数代码。

public string Foo { get; } = "SomeString";

public List<string> Genres { get; } = new List<string> { "Comedy", "Drama" };

You can find more information on this here

【讨论】:

    【解决方案4】:

    声明为readonly 的变量可以在构造函数中编写,但在支持该属性的语言中,在构造函数返回后无法修改。该限定符是作为语言特性提供的,因为对于值会根据构造函数参数而变化的字段(这意味着它们不能在构造函数启动之前初始化)但在构造函数返回后不必更改,它通常是必需的,但它是仅可用于作为字段公开的变量。 readonly-qualified 字段的语义在许多情况下对于公共成员来说是完美的,但对于类来说,将成员(甚至是不可变的成员)公开为属性而不是字段通常会更好。

    正如读写自动属性的存在允许类像普通字段一样容易地公开可变属性,只读自动属性的存在是为了允许类像readonly-qualified 字段一样容易地公开不可变属性。正如readonly-qualified 字段可以写在构造函数中一样,get-only 属性也是如此。

    【讨论】:

      【解决方案5】:

      这是a new feature in C#6,它允许您创建只读属性并从构造函数初始化它们的值(或在声明它们时内联)。

      如果您尝试在构造函数之外更改此属性的值,则会出现编译错误。

      它是只读的,一旦你初始化它的值(内联或在构造函数内部),你就不能改变它的值。

      【讨论】:

      • 那么,解释是什么? getter 的定义是什么?
      【解决方案6】:

      如果无法从构造函数(或自动属性初始化器)初始化只读属性,那么它将无用,因为它总是返回其类型的默认值(0 表示数字,null对于参考类型)。相同的语义适用于所有 C# 版本中的 readonly 字段。

      要定义真正的 getter-only 属性(不能从构造函数初始化),您需要指定它返回的内容作为定义的一部分:

      public int Foo { get { return 5; } }
      

      或者,在 C# 6 中更简洁:

      public int Foo => 5;
      

      【讨论】:

      • 不完全正确,只读属性对于在代码中封装某些条件非常有用。您可以编写 if 语句和几乎任何代码来评估其他属性或条件,并在每次读取属性时返回适当的值
      • @sebagomez:我不确定我是否明白你的意思——这不是我在我的例子中展示的吗?
      猜你喜欢
      • 2018-10-06
      • 2015-03-10
      • 1970-01-01
      • 1970-01-01
      • 2023-03-04
      • 2021-05-16
      • 2018-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多