什么是{get; 组; } C#中的语法?


577

我正在学习ASP.NET MVC,可以阅读英文文档,但是我不太了解这段代码中发生了什么:

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

这是什么意思{ get; set; }


4
通常要记住,设置者会使您的对象可变,这是个坏主意。吸气剂违反了“告诉对象该做什么,不要要求它提供信息并自己操纵它”。因此,通常,默认情况下不要添加setter和getter。通常,您将需要它们,但是在添加它们之前,应该始终找到真正的需求。特别是在生产代码中绝不应该使用setter(在任何可能的地方都力求不变性,当需要突变时,您应该要求它为您突变,而不是设置值)。
Bill K

8
只是添加一些内容...如果您不放置{get; set;},则创建字段,但如果放置,{get; set;}则创建属性。拥有属性可以使某些事情变得更容易,尤其是在使用反射时。
精一2015年

@Seichi也使用get-setter来创建一个字段,但是该字段是隐藏的,声明为私有的,并由自动创建的属性进行了修改;所有这些都是由编译器完成的。
乔纳森·拉莫斯

1
汽车属性不会违反私有领域的目的吗?
mireazma

Answers:


566

这是所谓的auto属性,本质上是以下内容的简写(类似的代码将由编译器生成):

private string name;
public string Name
{
    get
    {
        return this.name;
    }
    set
    {
        this.name = value;
    }
}

93
克劳斯,您能解释一下这段代码会发生什么吗?可能需要更详尽的解释才能受益。
TylerH

3
因此,可以肯定的是:这就像我是否重载了=运算符,但只针对一个特定元素,对吗?
Hi-Angel

9
为什么我们需要私有变量。:-/丢脸。
奥利弗·迪克森

2
@TylerH私有变量的原因是封装,get / set提供了获取或设置变量的“门”。尽管有很多原因不使用get / setter的原因,因为“门”可能会破坏私有变量的封装。(不应访问)
亚历山大

4
这可能很明显,但我想澄清一下,该速记并非从字面上看是速记。即,没有name创建私有变量。如果您尝试在类中引用此私有变量,它将失败。我不确定C#是如何做到的,但是它的行为就像是一个没有名称的私有变量,您无法在代码中访问它。
Denziloe

432

因此,据我所知,它{ get; set; }是一个“自动属性”,就像@Klaus和@Brandon所说的那样,是编写带有“后备字段”的属性的简写。因此,在这种情况下:

public class Genre
{
    private string name; // This is the backing field
    public string Name   // This is your property
    {
        get => name;
        set => name = value;
    }
}

但是,如果您像我一样(大约一个小时左右),则您实际上并不真正了解什么是属性访问者,并且您也不会对某些基本术语有最好的了解。MSDN是学习此类内容的绝佳工具,但对于初学者而言并不总是那么容易理解。因此,我将在这里尝试更深入地解释这一点。

get并且set访问者,这意味着他们能够在私有字段(通常是从支持字段)中访问数据和信息,并且通常可以从公共 属性中访问(如上例所示)。

无可否认,上面的陈述令人困惑,因此让我们来看一些示例。假设这段代码是指音乐流派。因此,在流派类别中,我们将需要不同流派的音乐。假设我们想要3种类型:嘻哈,摇滚和乡村。为此,我们将使用的名称来创建该类的新实例

Genre g1 = new Genre(); //Here we're creating a new instance of the class "Genre"
                        //called g1. We'll create as many as we need (3)
Genre g2 = new Genre();
Genre g3 = new Genre();

//Note the () following new Genre. I believe that's essential since we're creating a
//new instance of a class (Like I said, I'm a beginner so I can't tell you exactly why
//it's there but I do know it's essential)

现在,我们已经创建了Genre类的实例,我们可以使用上面设置的'Name' 属性来设置类型名称。

public string Name //Again, this is the 'Name' property
{ get; set; } //And this is the shorthand version the process we're doing right now 

通过编写以下代码,我们可以将名称“ g1”设置为嘻哈

g1.Name = "Hip Hop";

这里发生的事情有点复杂。就像我之前说的,getset从私人领域获得的信息,否则你将无法访问。get只能从该私有字段中读取信息并返回。set只能在该私有字段中写入信息。但是,有同时具有财产getset我们能够做到这两方面的功能。通过编写,g1.Name = "Hip Hop";我们专门使用set了Name属性中的函数

set使用名为的隐式变量value。基本上,这意味着您每次在中看到“值”时set,即表示变量。“值”变量。在编写时,g1.Name =我们使用=来传入value变量,在这种情况下为"Hip Hop"。因此,您基本上可以这样认为:

public class g1 //We've created an instance of the Genre Class called "g1"
{
    private string name;
    public string Name
    {
        get => name;
        set => name = "Hip Hop"; //instead of 'value', "Hip Hop" is written because 
                              //'value' in 'g1' was set to "Hip Hop" by previously
                              //writing 'g1.Name = "Hip Hop"'
    }
}

重要的是要注意上面的示例实际上不是用代码编写的。更多的是假设的代码,它表示后台发生的事情。

因此,既然我们已经设置Genre的g1实例的名称,我相信我们可以通过编写来获取名称

console.WriteLine (g1.Name); //This uses the 'get' function from our 'Name' Property 
                             //and returns the field 'name' which we just set to
                             //"Hip Hop"

如果我们运行它,我们将进入"Hip Hop"控制台。

因此,出于解释的目的,我还将使用输出完成示例

using System;
public class Genre
{
    public string Name { get; set; }
}

public class MainClass
{
    public static void Main()
    {
        Genre g1 = new Genre();
        Genre g2 = new Genre();
        Genre g3 = new Genre();

        g1.Name = "Hip Hop";
        g2.Name = "Rock";
        g3.Name = "Country";

        Console.WriteLine ("Genres: {0}, {1}, {2}", g1.Name, g2.Name, g3.Name);
    }
}

输出:

"Genres: Hip Hop, Rock, Country"

18
我个人只是将其注释掉set{name = value;} // 'value' here is equal to "Hip Hop"
maksymiuk

2
@iLoveUnicorns,它用于数据抽象。支持字段是包含实际数据的字段。该属性定义实际上定义了如何使用getset方法访问数据。我提供的链接在页面顶部有John Guttag的精彩引用。我建议您阅读他的书甚至参加免费的在线课程
Josie Thompson

2
我们不能只使用: public class Genre{public string Name;} 而不是: public class Genre{ public string Name { get; set; }}。我的意思是,为什么我们甚至需要{get; 组; }?
user2048204 '16

1
似乎我的担忧已经得到回应。如果以这种方式声明:“ public string Name {get; set;}”,则可以通过以下方式访问:g1.Name =“ Hip Hop”; -那么对象定向在哪里?我什至不需要所谓的“后备场”。就我而言,支持领域甚至不存在。因为我只访问公共领域。而且,如果公共字段是“公共”,则它不符合OO。让我们回到COBOL。
Baruch Atta

1
很好的答案,但是如果我们要学究,“ set”是一个变量,而不是访问器。
pythlang

100

这些是自动属性

基本上是另一种写有后备属性的属性的方法。

public class Genre
{
    private string _name;

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

7
什么叫“后备场”?
kn3l

4
@stackunderflow:备份字段是存储数据的位置。(使用时返回的结果get,并使用持久化set)。像橱柜,其getset打开的门。
Grant Thomas

5
@stackunderflow:在此答案中,后备字段为_name。在自动属性中,后备字段是隐藏的。
贾斯汀

36

这是这样做的简短方法:

public class Genre
{
    private string _name;

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

33

这是将数据成员公开显示的快捷方式,因此您无需显式创建私有数据成员。C#将为您创建一个私有数据成员。

您可以不使用此快捷方式就将数据成员公开,但是如果您决定更改数据成员的实现以具有某种逻辑,则需要中断该接口。简而言之,这是创建更灵活的代码的捷径。


2
凯尔西(Kelsey)-您能解释一下这种语法如何使它变得更“灵活”吗?我没看到 如果您要在setter或getter上添加任何“逻辑”,那么在以太坊情况下(有或没有私有数据),您仍然会破坏接口,并需要一些编码。
Baruch Atta

18

基本上,这是一个快捷方式:

class Genre{
    private string genre;
    public string getGenre() {
        return this.genre;
    }
    public void setGenre(string theGenre) {
        this.genre = theGenre;
    }
}
//In Main method
genre g1 = new Genre();
g1.setGenre("Female");
g1.getGenre(); //Female

5
这不能回答问题。OP在谈论财产。
theB

6
我知道属性“获取”和“设置”,这是一个有助于更好理解的示例
Jirson Tavera 2015年


6

它们是公共属性Name的访问者。

您将使用它们在Genre实例中获取/设置该属性的值。


6

那是一个自动实现的属性。从本质上讲,这是在C#中为类创建属性的一种简便方法,而无需为其定义私有变量。当获取或设置变量的值时不需要额外的逻辑时,通常使用它们。

您可以在《 MSDN的自动实现的属性编程指南》中阅读更多内容。


6
  • get / set模式提供了一种结构,该结构允许在实例化类的属性实例的设置(“ set”)或检索(“ get”)期间添加逻辑,当需要为实例化逻辑使用某些实例化逻辑时,此方法很有用。属性。

  • 属性只能具有“获取”访问器,这样做是为了使该属性为只读

  • 在实现获取/设置模式时,中间变量用作可以在其中放置值并提取值的容器。中间变量通常以下划线为前缀。此中间变量是私有的,以确保只能通过其get / set调用对其进行访问。请参阅Brandon的答案,因为他的答案演示了实现get / set的最常用语法约定。


5

这意味着,如果创建类型为Genre的变量,则可以将其作为属性访问

Genre oG = new Genre();
oG.Name = "Test";

5
当您不使用自动实现的属性时,仍然可以通过这种方式访问​​它。即,AIP与从外部进行访问无关,而与在类内部进行声明有关。
abatishchev 2011年

4

这种{ get; set; }语法称为自动属性,C#3.0语法

您必须使用Visual C#2008 / csc v3.5或更高版本进行编译。但是,您可以编译目标低至.NET Framework 2.0的输出(不需要运行时或支持此功能的类)。


4

在Visual Studio中,如果您X在类中定义了一个属性,并且只想将该类用作类型,则在构建项目后,您会收到一条警告,指出“字段X从未分配给它,并且始终具有其默认值值”

通过添加{ get; set; }X属性,你不会得到这个警告。

此外,在Visual Studio 2013和更高版本中,通过添加,{ get; set; }您可以查看对该属性的所有引用。

在此处输入图片说明


4

它基本上是简写。您可以public string Name { get; set; }像在许多示例中一样编写,但也可以编写:

private string _name;

public string Name
{
    get { return _name; }
    set { _name = value ; } // value is a special keyword here
}

为什么使用它?它可用于过滤对属性的访问,例如,您不希望名称包含数字。

让我举一个例子:

private class Person {
    private int _age;  // Person._age = 25; will throw an error
    public int Age{
        get { return _age; }  // example: Console.WriteLine(Person.Age);
        set { 
            if ( value >= 0) {
                _age = value; }  // valid example: Person.Age = 25;
        }
    }
}

正式称其为“自动实现的属性”,并且具有阅读(编程指南)的良好习惯。我还将推荐教程视频C#属性:为什么使用“ get”和“ set”


2

获取设置是对属性的访问修饰符。获取读取属性字段。Set设置属性值。获取就像只读访问。集就像只写访问。要将属性用作读写,必须同时使用get和set。


1
我认为获取不是访问修饰符,实际上它们是访问器。访问修饰符,如:公共,私有,内部等
罗希特阿罗拉

1

属性出现在右侧(RHS)时调用Get;当属性出现在'='符号的左侧(LHS)时调用Set。

对于自动实施的属性,背景字段在幕后起作用并且不可见。

例:

public string Log { get; set; }

而对于非自动实现的属性,后备字段是预先显示的,可以作为私有作用域变量看到。

例:

private string log;

public string Log
{
    get => log;
    set => log = value;
}

另外,这里值得一提的是“ getter”和“ setter”可以使用不同的“ backing field”


这似乎无法回答所问的问题。
TylerH

提供有关何时调用get&set的提示。上面提到的所有答案都给人一种印象,即get&set的支持字段是相同的。但事实并非如此。因此,我的回答与主要问题非常相关。希望你同意我的看法。
巴拉

对于自动生成的属性(即问题所要解决的问题),getter和setter不能使用不同的后备字段。只有一个后备领域。对于非汽车财产(这个问题没有问到),从概念上讲甚至根本没有后备领域。此外,您可以编写一个程序,该程序在赋值运算符的左侧带有一个吸气剂,而在赋值运算符的右侧带有一个setter的一个程序。因此,不仅所有这些信息都无法回答所提出的问题,而且所有这些信息都是错误的。
Servy '17

0

定义私有变量

在构造函数内部并加载数据

我已经创建了Constant并将数据从constant加载到Selected List类。

public  class GridModel
{
    private IEnumerable<SelectList> selectList;
    private IEnumerable<SelectList> Roles;

    public GridModel()
    {
        selectList = from PageSizes e in Enum.GetValues(typeof(PageSizes))
                       select( new SelectList()
                       {
                           Id = (int)e,
                           Name = e.ToString()
                       });

        Roles= from Userroles e in Enum.GetValues(typeof(Userroles))
               select (new SelectList()
               {
                   Id = (int)e,
                   Name = e.ToString()
               });
    }

  public IEnumerable<SelectList> Pagesizelist { get { return this.selectList; } set { this.selectList = value; } } 
  public IEnumerable<SelectList> RoleList { get { return this.Roles; } set { this.Roles = value; } }
  public IEnumerable<SelectList> StatusList { get; set; }

}

0

属性就像一个将私有变量与类的其他成员分开的层。从外界看来,属性只是一个字段,可以使用.Property访问属性

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

    public string LastName { get; set; }

    public string FullName => $"{FirstName} {LastName}";
}

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

    public string LastName { get; set; }

    public string FullName { get { return $"{FirstName} {LastName}"; } }
}

FullName是一个属性。带箭头的是快捷方式。从外部世界,我们可以这样访问FullName:

var person = new Person();
Console.WriteLine(person.FullName);

呼叫者不在乎您如何实现FullName。但是在类中,您可以根据需要更改FullName。

查看Microsoft文档以获取更多详细说明:

https://docs.microsoft.com/zh-cn/dotnet/csharp/properties

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.