Tôi nên thích các thuộc tính có hoặc không có các lĩnh vực tư nhân?


16

Cơ sở mã hiện đang làm việc có quy ước sử dụng các trường riêng và thuộc tính công cộng. Ví dụ, hầu hết các lớp có các thành viên được định nghĩa như thế này:

// Fields
private double _foo;
private double _bar;
private double _baz;

// Properties
public double Foo
{
    get{ return _foo; }
    set{ _foo = value; }
}

public double Bar
{
    get{ return _bar; }
    set{ _bar = value; }
}

public double Baz
{
    get{ return _baz; }
}

Tôi biết những thứ này có thể được viết lại mà không có thuộc tính riêng tư bên trong của chúng:

public double Foo{ get; set; }
public double Bar{ get; set; }
public double Baz{ get; private set; }

Tôi muốn một số đầu vào về điều này:

  • Có một lý do chính đáng để thích phong cách cũ hơn, rõ ràng hơn so với phong cách mới hơn, súc tích hơn?
  • Tôi nên viết bất kỳ lớp mới nào bằng cách sử dụng kiểu súc tích, hay tôi nên cố gắng khớp mã cũ hơn để thống nhất? Là sự nhất quán có đủ giá trị trong trường hợp này để biện minh cho định dạng cũ hơn?


@PeterK. Nhiều thông tin. Không trả lời liệu tôi có nên lo lắng về việc giữ đúng phong cách của phần còn lại của chương trình hay không, nếu đó là một chi tiết đủ nhỏ không quan trọng.
KChaloux

@KChaloux: Đã hiểu! Đó là lý do tại sao nó là một bình luận, không phải là một câu trả lời. :-)
Peter K.

@PeterK. Hội chợ 'nuff = p
KChaloux

1
Một lý do khác để không thay đổi là nếu bất cứ điều gì được chuyển qua dây với WCF - thuộc tính tự động có vấn đề về hợp đồng (do các ký tự không hợp lệ trong tên trường sao lưu được tạo bởi .NET)
Leon

Câu trả lời:


16

Có một vài trường hợp vẫn yêu cầu kiểu "cũ" hơn:

A: Các loại bất biến sử dụng tính bất biến do ngôn ngữ cung cấp. Công cụ readonlysửa đổi trong C # đóng băng giá trị đó sau khi xây dựng. Không có cách nào để bắt chước điều này với các thuộc tính được triển khai tự động (chưa).

public sealed class FooBarBazInator
{
    private readonly double foo;

    public FooBarBazInator(double foo)
    {
        this.foo = foo;
    }

    public double Foo
    {
        get
        {
            return this.foo;
        }
    }
}

B: Getters / setters của bạn có bất kỳ logic nào. Mã WPF và Silverlight (và tương tự) được liên kết dữ liệu với các lớp của bạn sẽ triển khai INotifyPropertyChangednhư vậy:

public class FooBarBazInator : INotifyPropertyChanged
{
    private double foo;

    public event PropertyChangedEventHandler PropertyChanged;

    public double Foo
    {
        get
        {
            return this.foo;
        }

        set
        {
            this.foo = value;
            this.RaisePropertyChanged("Foo");
        }
    }

    private void RaisePropertyChanged(string propertyName)
    {
        var propertyChanged = this.PropertyChanged;

        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Khác với những người khác, tôi muốn nói sử dụng phong cách mới. Giữ cho mã của bạn ngắn gọn và cung cấp ít diện tích bề mặt hơn cho các lỗi phát sinh. Ngoài ra, nếu cần thay đổi để bao gồm logic, nó sẽ không tương thích với chữ ký.


2
Mọi người dường như đồng ý về việc đi với phong cách mới. Bạn nhận được +1 và tín dụng câu trả lời cho tôi biết về sự cần thiết của một lĩnh vực với công cụ readonlysửa đổi, điều mà tôi không biết. = D
KChaloux

3
Một số (bao gồm cả tôi) xem xét các thuộc tính tự động với người truy cập riêng tư đủ tốt cho các thuộc tính bất biến. Đúng, chúng có thể không thực sự bất biến, nhưng bạn chỉ cần cẩn thận không sử dụng setter bên ngoài hàm tạo.
Svick

2
một reaon khác là nếu bạn muốn truyền giá trị vì refnó không hoạt động với các thuộc tính, vì vậy bạn cần trường
stijn

1
Một công cụ như Fody có thể thực hiện INotifyPropertyChangedmà không cần các trường sao lưu rõ ràng. github.com/Fody/PropertyChanged
Sebastian Redl

3
Lưu ý: C # 6 cho phép "thuộc tính tự động chỉ getter" cung cấp trong một dòng duy nhất ví dụ "A" của tôi đang làm gì.
Jesse C. Choper

6

Tôi sẽ nói rằng có trường sao lưu rõ ràng chỉ là vô ích: nó làm cho mã của bạn dài hơn và khó đọc hơn. Nó cũng thêm tiềm năng lỗi:

public double Bar
{
    get { return _baz; }
    set { _bar = value; }
}

Tôi nghĩ rằng một lỗi như thế này có thể xảy ra khá dễ dàng và sẽ khá khó để phát hiện ra.

Và nếu bạn muốn tính nhất quán, hãy làm theo cách khác: thay đổi mã sử dụng các trường sao lưu thành mã sử dụng các thuộc tính tự động. Điều này đặc biệt dễ dàng nếu bạn sử dụng một công cụ tái cấu trúc như ReSharper (và nếu bạn không sử dụng thứ gì đó tương tự, tôi nghĩ bạn nên bắt đầu).

Tất nhiên, vẫn có trường hợp cần có trường sao lưu là cần thiết, nhưng tôi nghĩ điều đó không liên quan đến câu hỏi này.


Tôi thực sự đã làm điều đó trên một vài lĩnh vực cũ khi tái cấu trúc mã ... thật là khó khăn.
KChaloux

1

Mặc dù câu hỏi khá cũ nhưng tôi đã nghĩ đến việc thêm vài điểm mà tôi đọc được từ một cuốn sách đáng nói ở đây.

  1. Các công cụ tuần tự hóa thời gian chạy vẫn duy trì tên của tệp được gửi trong một luồng được tuần tự hóa. Tên của trường sao lưu cho thuộc tính được triển khai tự động (AIP) được xác định bởi trình biên dịch và nó thực sự có thể thay đổi tên của trường sao lưu này mỗi khi bạn biên dịch lại mã của mình, phủ nhận khả năng khử lưu trữ các thể hiện của bất kỳ loại nào có chứa AIP. Vì vậy, không sử dụng AIP với bất kỳ loại nào bạn định nối tiếp hoặc giải tuần tự hóa.

  2. Khi gỡ lỗi, bạn không thể đặt điểm dừng trên phương thức nhận hoặc đặt AIP, do đó bạn không thể dễ dàng phát hiện khi ứng dụng nhận hoặc đặt thuộc tính này. Bạn có thể đặt điểm dừng trên điểm dừng được triển khai thủ công


3
# 1 - Hầu hết các serial serial bỏ qua các thuộc tính / trường riêng theo mặc định; Tôi chưa bao giờ gặp phải những vấn đề bạn đề cập. # 2 - Điều này được cố định trong VS2015 và có thể được khắc phục trong VS2013. Xem bài viết này của Tạp chí Visual Studio .
Brian

-3

Có một lý do chính đáng để thích phong cách cũ hơn, rõ ràng hơn so với phong cách mới hơn, súc tích hơn?

Không hẳn vậy. Mặc dù tôi sẽ lập luận rằng bất cứ khi nào bạn có một tài sản như thế, bạn nên sử dụng một lĩnh vực công cộng để bắt đầu.

Tôi nên viết bất kỳ lớp mới nào bằng cách sử dụng kiểu súc tích, hay tôi nên cố gắng khớp mã cũ hơn để thống nhất? Là sự nhất quán có đủ giá trị trong trường hợp này để biện minh cho định dạng cũ hơn?

Giả sử bạn bỏ qua lời khuyên ở trên và có thuộc tính thông qua, tôi sẽ không nhắm đến phong cách phù hợp. Lý tưởng nhất là bạn sẽ quay lại và cấu trúc lại kiểu cũ thành kiểu mới để phù hợp, nhưng cơ hội để mọi người đọc sai mã đó là mỏng.



@svick - Bah. Trừ khi bạn đang phản ánh vào loại không có sự khác biệt. Nếu bạn công khai hiển thị loại dưới dạng giao diện dịch vụ hoặc thư viện, bạn sẽ hiển thị giao diện sẽ yêu cầu một thuộc tính. OP không làm bất cứ điều gì trong số đó.
Telastyn

2
Không có lý do kỹ thuật trong những trường hợp hạn chế này. Đừng quên các thuộc tính hoạt động khác nhau trong trình gỡ lỗi, sơ đồ lớp, intellisense và chỉ khi bạn nghĩ rằng bạn không thực hiện phản chiếu, thì khung công tác .NET là. WinForms, WPF và một số thành phần khác sử dụng sự phản chiếu trong nội bộ và chúng xử lý các thuộc tính riêng biệt, vì vậy lời khuyên sử dụng các trường công khai, sẽ không được nhiều nhà phát triển trên trang này nhận được.
Kevin McCormick

1
@KevinMcCormick và khung hoạt động hoàn toàn tốt (từ những gì tôi hiểu) với các trường. Bây giờ nó không thực sự quan trọng vì có các thuộc tính tự động, nhưng vấn đề lớn hơn là làm cho mọi thứ trở nên công khai ngay từ đầu. Xa, quá nhiều người nghĩ rằng chỉ đơn giản là tạo ra những thứ thuộc tính bằng cách nào đó đã loại bỏ chúng khỏi 'đừng tạo ra các lĩnh vực công cộng'.
Telastyn

2
Khung xử lý chúng khác nhau: thử sử dụng trường công khai trong EF POCO, liên kết nó với DataGridView, sử dụng PropertyGrid, v.v. Tôi vừa thực hiện tìm kiếm nhanh trong trình dịch ngược của mình sang Type.GetPropericat / GetProperty và Framework thực hiện các cuộc gọi đến phương thức này hàng trăm lần, nhưng không đến GetField. Điểm mấu chốt là chúng khác nhau và khuyến nghị luôn luôn sử dụng các thuộc tính cho dữ liệu công khai dựa trên một phần thực tế này. Điều này không loại trừ việc sử dụng các trường bao giờ, nhưng trường hợp đó cần biện minh. Tuy nhiên, điểm khác của bạn chắc chắn là đúng, việc phơi bày dữ liệu công khai một cách bất cẩn luôn là một ý tưởng tồi.
Kevin McCormick
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.