【问题标题】:I need someone to correct my thinking on C# Properties (get & set)我需要有人来纠正我对 C# Properties (get and set) 的看法
【发布时间】:2022-12-24 19:30:13
【问题描述】:

我很难理解属性是如何“连接”到支持字段的。我已经建立了一个常见的例子。我经常看到 get 和 set 简化为 {get;放;}。这是否仅在存在一个字段时才适用,或者它仍然可以与两个相同类型的字段一起使用。如果它确实有效,那么此代码中的名称属性是否代表名称或地址或两者?如果将存储在那里的信息在公共财产中存储/访问,我很难理解私有字段的重要性。这有意义吗?

using System;

namespace MyApplication
{
  class Program
  {
    static void Main(string[] args)
    {
      Person myObj = new Person();
      myObj.Name = "Liam";
      Console.WriteLine(myObj.Name);
    }
  }
  class Person
  {
    private string name;
    private string address; 
    public string Name {get; set;}  
  }
  
}

【问题讨论】:

  • 属性本身不一定与支持字段“连接”。对于自动实现的属性(那些只有 {get;}{ get; set; } 声明的属性),编译器会生成一个支持字段,而不是你。如果您好奇的话,可以通过反射发现支持字段。对于具有显式实现的其他属性(即,不是自动实现的),它们是否由支持字段支持取决于编写的 getter/setter 代码......
  • 当前示例中的内容是 auto property。基本上,当您像那样简化getset 时,编译器实际上会自行为它创建一个支持字段。 get返回字段值,set设置。您添加自己的私有字段而不将属性连接到它仍然会使该属性成为自动属性,因此您的私有字段根本没有被使用。
  • 在您的情况下,属性 Name 与字段 name 完全无关。 20 年前,当 .NET 首次发布时,您将实现一个像这样的简单属性:public string Name { get { return name; } set { name = value; } }。然后语言得到了自动属性带有隐藏的支持字段。于是public string Name { get; set; }诞生了,不需要明确的支持字段
  • 属性的目的是访问控制。具有私有支持字段的公共属性为内部类提供了不受限制的读取和更改私有字段的访问权限,而公共属性可以包含逻辑,该逻辑对当前类之外的哪些代码可以get来自该字段或@ 987654335@外地来。

标签: c# properties get set accessor


【解决方案1】:

你不需要具有支持字段的属性。特别是如果它们是公开可读可写的。

没有支持字段

有许多没有支持字段的选项。

公共 setter 和 getter

// inline value initialisation
var p1 = new Person()
{
    Name = "John"
};

// instantiation + setting
var p2 = new Person();
p2.Name = "John";

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

公共 getter,私有 setter

// inline value initialisation
var p1 = new Person("John");

class Person
{
    public string Name {get; private set;} 

    public Person(string name)
    {
        this.Name = name;
    }
}

要么 ...

// inline value initialisation
var p1 = new Person();
p1.SetSomeProps("John");

class Person
{
    public string Name {get; private set;} 

    public void SetSomeProps(string name)
    {
        this.Name = name;
    }
}

有支持字段

// inline value initialisation
var p1 = new Person()
{
    Name = "John"
};

// instantiation + setting
var p2 = new Person();
p2.Name = "John";

class Person
{
    private string theName = string.Empty;

    public string Name
    {
        get
        {
            return this.theName;
        }

        set(string value)
        {
            this.theName = value;
        }

    }  
}

【讨论】:

  • 从技术上讲,像 public string Name {get; set;} 这样的自动实现的属性使用支持字段。只是不是程序员,而是编译器将为自动实现的属性(因此称为“自动”)声明支持字段。自动实现属性的支持字段就在那里,可以通过反射和检查编译器生成的 IL 代码来发现。所以,从某种意义上说,自动实现的道具没有后台是错误的。正确:自动实现的 props 不需要程序员明确地为它们声明一个支持字段
  • @MySkullCaveIsADarkPlace 我很清楚这一点,但这个例子的关键是开发人员没有用它们编写代码。
【解决方案2】:

public string Name {get; set;} 是一个 auto-implemented property,它有自己的支持字段,由编译器生成,名称类似于 <Name>k__BackingField。您可以使用反编译器查看它,例如在线反编译器 - sharplab.io 它将显示类似这样的输出:

internal class Person
{
    private string name;

    private string address;

    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private string <Name>k__BackingField;

    public string Name
    {
        [CompilerGenerated]
        get
        {
            return <Name>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Name>k__BackingField = value;
        }
    }
}

请注意,生成的属性名称以 &lt; 符号开头,不能 应用程序开发人员将其用作标识符名称的一部分,因此编译器可以避免与开发人员定义的命名冲突。

因此,如您所见,您的Name 属性将不会连接到在同一类中声明的nameaddress 字段。

如果您需要,您可以手动定义带有支持字段的属性(通常是在有一些额外的逻辑时完成):

class Person
{
    private string _name;

    public string Name
    {
        get => _name;
        set => _name = value;
    }
}

【讨论】:

    猜你喜欢
    • 2015-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-12
    • 1970-01-01
    • 1970-01-01
    • 2022-01-12
    • 1970-01-01
    相关资源
    最近更新 更多