{Nhận được; bộ; } cú pháp trong C #?


577

Tôi đang học ASP.NET MVC và tôi có thể đọc tài liệu tiếng Anh, nhưng tôi không thực sự hiểu những gì đang xảy ra trong mã này:

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

Điều này có nghĩa là { get; set; }gì : ?


4
Nói chung hãy nhớ - setters làm cho đối tượng của bạn có thể thay đổi, một ý tưởng tồi. getters vi phạm "Nói cho đối tượng biết phải làm gì, đừng hỏi nó về thông tin và tự mình thao túng nó". Vì vậy, nói chung, không thêm setters và getters theo mặc định. Bạn sẽ cần chúng, thường xuyên, nhưng bạn nên luôn luôn tìm thấy một nhu cầu thực sự trước khi bạn thêm chúng. Cụ thể là setters hầu như không bao giờ được sử dụng trong mã sản xuất (Phấn đấu cho tính bất biến bất cứ khi nào có thể, và khi cần đột biến, bạn nên yêu cầu nó biến đổi cho bạn, không đặt giá trị).
Bill K

8
Chỉ cần thêm một cái gì đó ... Nếu bạn không đặt {get; set;}bạn đang tạo Trường nhưng nếu bạn đặt thì {get; set;}bạn đang tạo Tài sản . Có một tài sản có thể làm cho một số điều dễ dàng hơn đặc biệt là khi làm việc với Reflection.
Seichi

@Seichi sử dụng get-setter cũng tạo Trường, nhưng trường này bị ẩn, được khai báo là riêng tư và được sửa đổi bởi các thuộc tính được tạo tự động; tất cả điều đó được thực hiện bởi trình biên dịch.
Jonathan Ramos

1
tài sản tự động không đánh bại mục đích của các lĩnh vực tư nhân ?
mireazma

Câu trả lời:


567

Đây được gọi là thuộc tính tự động và về cơ bản là một tốc ký cho các mục sau (mã tương tự sẽ được trình biên dịch tạo ra):

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

93
Klaus, bạn có thể giải thích những gì sẽ xảy ra với mã này? Nó có thể được hưởng lợi từ một lời giải thích kỹ lưỡng hơn.
TylerH

3
Vì vậy, chỉ để chắc chắn: nó giống như nếu tôi làm quá tải =toán tử, nhưng chỉ cho một yếu tố cụ thể, phải không?
Hi-Angel

9
Tại sao chúng ta cần var riêng. :-/ xấu hổ.
Oliver Dixon

2
@TylerH Lý do cho biến riêng là đóng gói, get / set cung cấp "cổng" để lấy hoặc đặt biến. Mặc dù có nhiều lý do để không sử dụng get / setters vì "cổng" có thể phá vỡ sự đóng gói của biến riêng. (không nên truy cập)
Alexander

4
Có thể rõ ràng, nhưng tôi muốn làm rõ rằng tốc ký không thực sự là một tốc ký cho điều đó. Đó là, không có biến riêng tư nameđược tạo ra. Nếu bạn đã cố gắng tham chiếu biến riêng tư này trong lớp, nó sẽ thất bại. Tôi không chắc chắn làm thế nào C # làm điều đó, nhưng nó hoạt động như thể có một biến riêng không có tên, mà bạn không thể truy cập trong mã của mình.
Denziloe

432

Vì vậy, theo tôi hiểu, đây { get; set; }là một "tài sản tự động" giống như @Klaus và @Brandon nói là viết tắt cho việc viết một tài sản với "trường sao lưu". Vì vậy, trong trường hợp này:

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

Tuy nhiên nếu bạn đang như tôi - khoảng một giờ hoặc lâu hơn trước - bạn không thực sự hiểu những gì thuộc tínhaccessors được, và bạn không có sự hiểu biết tốt nhất của một số thuật ngữ cơ bản trong hai. MSDN là một công cụ tuyệt vời để học những thứ như thế này nhưng không phải lúc nào cũng dễ hiểu cho người mới bắt đầu. Vì vậy, tôi sẽ cố gắng giải thích điều này sâu hơn ở đây.

getsetbộ truy xuất , có nghĩa là họ có thể truy cập dữ liệu và thông tin trong tin lĩnh vực (thường là từ một lĩnh vực sao lưu ) và thường làm như vậy từ công thuộc tính (như bạn có thể thấy trong ví dụ trên).

Không thể phủ nhận rằng tuyên bố trên khá khó hiểu, vì vậy hãy đi vào một số ví dụ. Giả sử mã này đề cập đến các thể loại âm nhạc. Vì vậy, trong lớp Thể loại, chúng tôi sẽ muốn các thể loại âm nhạc khác nhau. Giả sử chúng ta muốn có 3 thể loại: Hip Hop, Rock và Country. Để làm điều này, chúng ta sẽ sử dụng tên của Class để tạo các thể hiện mới của lớp đó.

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)

Bây giờ chúng ta đã tạo các instance của lớp Thể loại chúng ta có thể thiết lập những cái tên thể loại bằng 'Tên' tài sản đó là cách thiết lập ở trên.

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

Chúng ta có thể đặt tên của 'g1' thành Hip Hop bằng cách viết như sau

g1.Name = "Hip Hop";

Những gì đang xảy ra ở đây là loại phức tạp. Như tôi đã nói trước đây getsettruy cập thông tin từ các lĩnh vực riêng tư mà bạn không thể truy cập. getchỉ có thể đọc thông tin từ lĩnh vực riêng tư và trả lại. setchỉ có thể viết thông tin trong lĩnh vực riêng tư đó. Nhưng bằng cách có một tài sản với cả hai getsetchúng tôi có thể thực hiện cả hai chức năng đó. Và bằng cách viết, g1.Name = "Hip Hop";chúng tôi đặc biệt sử dụngset chức năng từ thuộc tính Tên của chúng tôi

setsử dụng một biến ẩn được gọi là value. Về cơ bản điều này có nghĩa là bất cứ khi nào bạn thấy "giá trị" bên trong set, nó đề cập đến một biến; biến "giá trị". Khi chúng ta viết, g1.Name =chúng ta sử dụng biến =để chuyển trong valuebiến trong trường hợp này là "Hip Hop". Vì vậy, về cơ bản bạn có thể nghĩ về nó như thế này:

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"'
    }
}

Điều quan trọng cần lưu ý là ví dụ trên không thực sự được viết trong mã. Đó là nhiều hơn một mã giả thuyết đại diện cho những gì đang diễn ra trong nền.

Vì vậy, bây giờ chúng ta đã đặt Tên của thể hiện g1 của Thể loại , tôi tin rằng chúng ta có thể lấy tên bằng cách viết

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"

và nếu chúng ta chạy nó, chúng ta sẽ nhận được "Hip Hop" trong bảng điều khiển.

Vì vậy, với mục đích của lời giải thích này, tôi cũng sẽ hoàn thành ví dụ với kết quả đầu ra

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);
    }
}

Đầu ra:

"Genres: Hip Hop, Rock, Country"

18
Cá nhân tôi sẽ chỉ nhận xét như vậyset{name = value;} // 'value' here is equal to "Hip Hop"
maksymiuk

2
@iLoveUnicorns, nó có mục đích trừu tượng hóa dữ liệu . Trường sao lưu là những gì chứa dữ liệu thực tế. Định nghĩa thuộc tính thực sự xác định cách dữ liệu được truy cập với getsetcác phương thức. Liên kết tôi cung cấp có một trích dẫn tuyệt vời từ John Guttag ở đầu trang. Tôi sẽ khuyên bạn nên đọc cuốn sách của anh ấy hoặc thậm chí tham gia khóa học trực tuyến miễn phí này
Josie Thompson

2
Chúng ta không thể sử dụng: public class Genre{public string Name;} thay vì : public class Genre{ public string Name { get; set; }}. Ý tôi là, tại sao chúng ta thậm chí cần {get; bộ; }?
dùng2048204

1
Có vẻ như mối quan tâm của tôi đã được lặp lại. Nếu bạn khai báo theo cách này: "Tên chuỗi công khai {get; set;}" và bạn truy cập theo cách này: g1.Name = "Hip Hop"; - vậy thì Định hướng đối tượng ở đâu? Tôi thậm chí không cần cái gọi là "trường ủng hộ". Trường sao lưu thậm chí không tồn tại, theo như tôi nghĩ. Bởi vì tôi chỉ truy cập vào lĩnh vực công cộng. Và nếu trường công khai là "công khai" thì nó không tuân thủ OO. Tất cả chúng ta hãy quay trở lại với COBOL.
Baruch Atta

1
Câu trả lời tuyệt vời, nhưng nếu chúng ta đang trở thành người phạm tội, thì bộ Set là một kẻ đột biến, không phải là người truy cập.
pythlang

100

Những người đang có đặc tính tự động

Về cơ bản một cách khác để viết một tài sản với một trường sao lưu.

public class Genre
{
    private string _name;

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

7
Cái gì gọi là "trường ủng hộ"?
kn3l

4
@stackunderflow: Trường sao lưu là nơi lưu trữ dữ liệu. (những gì được trả lại khi sử dụng get, và tiếp tục sử dụng set). Giống như cái tủ để getsetmở cánh cửa.
Grant Thomas

5
@stackunderflow: Trong câu trả lời này, trường sao lưu là _name. Trong thuộc tính tự động, trường sao lưu được ẩn.
Justin

36

Đây là cách ngắn để làm điều này:

public class Genre
{
    private string _name;

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

33

Đó là một lối tắt để hiển thị các thành viên dữ liệu dưới dạng công khai để bạn không cần phải tạo một thành viên dữ liệu riêng tư một cách rõ ràng. C # sẽ tạo một thành viên dữ liệu riêng tư cho bạn.

Bạn chỉ có thể đặt thành viên dữ liệu của mình ở chế độ công khai mà không cần sử dụng phím tắt này nhưng sau đó nếu bạn quyết định thay đổi việc thực hiện thành viên dữ liệu để có một số logic thì bạn sẽ cần phải phá vỡ giao diện. Vì vậy, trong ngắn hạn, nó là một phím tắt để tạo mã linh hoạt hơn.


2
Kelsey - bạn có thể giải thích cách cú pháp này làm cho nó trở thành mã "linh hoạt" hơn không? Tôi không thấy nó. Nếu bạn thêm bất kỳ "logic" nào vào setter hoặc getter, thì trong trường hợp ether (có hoặc không có dữ liệu riêng tư), bạn vẫn sẽ phá vỡ giao diện, vì nó là như vậy, và cần một số mã hóa.
Baruch Atta

18

Về cơ bản, đó là một lối tắt của:

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
Điều này không trả lời câu hỏi. OP đã nói về tài sản.
theB

6
tôi biết các thuộc tính Get and Set, đó là một ví dụ giúp hiểu rõ hơn
Jirson Cheesa


6

Họ là những người truy cập cho Tên tài sản công cộng.

Bạn sẽ sử dụng chúng để nhận / đặt giá trị của thuộc tính đó trong thể hiện của Thể loại.


6

Đó là một tài sản tự động thực hiện. Về cơ bản, đây là cách viết nhanh các thuộc tính cho một lớp trong C #, mà không phải xác định các biến riêng cho chúng. Chúng thường được sử dụng khi không cần thêm logic khi nhận hoặc đặt giá trị của biến.

Bạn có thể đọc thêm về Hướng dẫn lập trình thuộc tính tự động triển khai của MSDN .


6
  • Mẫu get / set cung cấp cấu trúc cho phép thêm logic trong khi cài đặt ('set') hoặc truy xuất ('get') của một thể hiện thuộc tính của một lớp khởi tạo, có thể hữu ích khi cần một số logic khởi tạo cho bất động sản.

  • Một thuộc tính có thể chỉ có trình truy cập 'get', được thực hiện để làm cho thuộc tính đó chỉ đọc

  • Khi thực hiện mẫu get / set, một biến trung gian được sử dụng làm vùng chứa trong đó giá trị có thể được đặt và giá trị được trích xuất. Biến trung gian thường được thêm tiền tố với dấu gạch dưới. biến trung gian này là riêng tư để đảm bảo rằng nó chỉ có thể được truy cập thông qua các lệnh gọi get / set của nó. Xem câu trả lời từ Brandon, vì câu trả lời của anh ấy thể hiện các quy ước cú pháp được sử dụng phổ biến nhất để thực hiện get / set.


5

Điều này có nghĩa là nếu bạn tạo một biến thể loại Thể loại, bạn sẽ có thể truy cập biến đó dưới dạng một thuộc tính

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

5
Khi bạn không sử dụng các thuộc tính được triển khai tự động, bạn vẫn có thể truy cập nó theo cách này. tức là AIP không phải là về truy cập từ bên ngoài, mà là về khai báo bên trong một lớp.
abatishchev

4

{ get; set; }Cú pháp như vậy được gọi là thuộc tính tự động, cú pháp C # 3.0

Bạn phải sử dụng Visual C # 2008 / csc v3.5 trở lên để biên dịch. Nhưng bạn có thể biên dịch đầu ra nhắm mục tiêu thấp như .NET Framework 2.0 (không cần thời gian chạy hoặc các lớp để hỗ trợ tính năng này).


4

Trong Visual Studio, nếu bạn xác định một Xthuộc tính trong một lớp và bạn chỉ muốn sử dụng lớp này làm loại, sau khi xây dựng dự án của bạn, bạn sẽ nhận được cảnh báo rằng "Trường X không bao giờ được gán cho và sẽ luôn có mặc định giá trị " .

Bằng cách thêm một { get; set; }đến Xbất động sản, bạn sẽ không nhận được cảnh báo này.

Ngoài Visual Studio 2013 và các phiên bản cao hơn, bằng cách thêm { get; set; }bạn có thể xem tất cả các tham chiếu đến thuộc tính đó.

nhập mô tả hình ảnh ở đây


4

Về cơ bản nó là một tốc ký. Bạn có thể viết public string Name { get; set; }như trong nhiều ví dụ, nhưng bạn cũng có thể viết nó:

private string _name;

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

Tại sao nó được sử dụng? Nó có thể được sử dụng để lọc quyền truy cập vào một thuộc tính, ví dụ bạn không muốn tên bao gồm số.

Tôi sẽ cho bạn một ví dụ:

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;
        }
    }
}

Chính thức được gọi là Thuộc tính tự động triển khai và thói quen tốt để đọc ( hướng dẫn lập trình ). Tôi cũng muốn giới thiệu video hướng dẫn Thuộc tính C #: Tại sao nên sử dụng "get" và "set" .


2

Nhận được thiết lập là sửa đổi truy cập vào tài sản. Nhận đọc các lĩnh vực tài sản. Đặt giá trị thuộc tính. Nhận giống như truy cập chỉ đọc. Đặt giống như truy cập chỉ ghi. Để sử dụng thuộc tính như đọc ghi cả get và set phải được sử dụng.


1
Tôi nghĩ rằng get set không phải là sửa đổi truy cập, vì họ là người truy cập. Công cụ sửa đổi truy cập giống như: công khai, riêng tư, nội bộ, v.v.
Rohit Arora

1

Nhận được gọi khi thuộc tính xuất hiện ở phía bên phải (RHS) Bộ được gọi khi thuộc tính xuất hiện ở phía bên trái (LHS) của biểu tượng '='

Đối với thuộc tính được triển khai tự động, trường sao lưu hoạt động phía sau cảnh và không hiển thị.

Thí dụ:

public string Log { get; set; }

Trong khi đối với một thuộc tính không được triển khai tự động, trường sao lưu là trả trước, hiển thị dưới dạng một biến phạm vi riêng.

Thí dụ:

private string log;

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

Ngoài ra, điều đáng lưu ý ở đây là 'getter' và 'setter' có thể sử dụng 'trường sao lưu' khác nhau


Điều này dường như không trả lời câu hỏi.
TylerH

Cung cấp gợi ý về khi get & set được gọi. Tất cả các câu trả lời được đề cập ở trên, tạo ấn tượng rằng trường sao lưu cho get & set là như nhau. Nhưng nó không phải là trường hợp. Vì vậy, câu trả lời của tôi rất liên quan đến câu hỏi chính. Hy vọng bạn đồng ý với tôi.
Bala

Đối với một thuộc tính được tạo tự động, đó là những gì câu hỏi yêu cầu, không thể có các trường sao lưu khác nhau được sử dụng cho getter và setter; chỉ có một lĩnh vực ủng hộ. Đối với một tài sản không tự động (mà câu hỏi không hỏi về) thậm chí về mặt khái niệm có thể không có trường hỗ trợ. Ngoài ra, bạn có thể viết chương trình với một getter ở phía bên trái của toán tử gán và một chương trình với setter ở phía bên phải của toán tử gán. Vì vậy, không chỉ tất cả các thông tin này không trả lời câu hỏi được hỏi, mà tất cả cũng sai.
Phục vụ

0

Xác định các biến riêng

Bên trong Trình xây dựng và tải dữ liệu

Tôi đã tạo Constant và tải dữ liệu từ hằng vào lớp Danh sách đã chọn.

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

Một thuộc tính giống như một lớp ngăn cách biến riêng tư với các thành viên khác của một lớp. Từ thế giới bên ngoài, cảm giác như một tài sản chỉ là một lĩnh vực, một tài sản có thể được truy cập bằng cách sử dụng .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 là một tài sản. Một trong những mũi tên là một phím tắt. Từ thế giới bên ngoài, chúng ta có thể truy cập FullName như thế này:

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

Người gọi không quan tâm đến cách bạn triển khai FullName. Nhưng bên trong lớp bạn có thể thay đổi FullName bất cứ điều gì bạn muốn.

Kiểm tra Tài liệu Microsoft để được giải thích chi tiết hơn:

https://docs.microsoft.com/en-us/dotnet/csharp/properies

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.