2009-03-06 33 views
7

Khi thiết lập một số thuộc tính kiểu tham chiếu cho dự án tôi đang làm việc, tôi đã xem xét một số thuộc tính cần thiết để được sử dụng đúng cách và không bao giờ được rỗng. Tôi đã nhìn thấy một vài cách để xử lý điều này và không thể thực sự xác định xem có bất kỳ hạn chế lớn nào đối với bất kỳ cách chính nào mà tôi đã thấy để xử lý việc này hay không. Tôi muốn nhận được ý kiến ​​của cộng đồng về cách tốt nhất để xử lý vấn đề này và những hạn chế tiềm năng đối với từng phương pháp có thể là gì.Xử lý C# Các thuộc tính không được rỗng

Cho một lớp đơn giản, tôi đã nhìn thấy một số cách để xử lý đảm bảo một tài sản không bao giờ có một phiên bản rỗng của lớp này trong một tài sản

public class MyClass 
{ 
    //Some collection of code 
} 

Lựa chọn 1 - Khởi tạo các cửa hàng ủng hộ

public class OtherClass1 
    { 
     private MyClass _mC = new MyClass(); 
     public MyClass MC 
     { 
      get { return _mC; } 
      set { _mC = value; } 
     } 
    } 

Lựa chọn 2 - khởi tạo tài sản trong các nhà xây dựng

public class OtherClass2 
    { 
     public MyClass MC { get; set; }  

     public OtherClass2() 
     { 
      MC = new MyClass(); 
     } 
    } 

Opti vào ngày 3 - Bắt đầu xử lý khi cần thiết trong Getter

public class OtherClass3 
    { 
     private MyClass _mC; 
     public MyClass MC 
     { 
      get 
      { 
       if (_mC == null) 
        _mC = new MyClass(); 
       return _mC; 
      } 
      set { _mC = value; } 
     } 
    } 

Tôi chắc chắn có nhiều cách khác, nhưng đây là những cách mà tôi nghĩ đến. Tôi chủ yếu là cố gắng để xác định xem có một thực hành tốt nhất được thành lập về điều này hoặc nếu có một mối quan tâm cụ thể với bất kỳ ở trên.

Chúc mừng,

Steve

+2

Dưới đây là một cú pháp "get" nhỏ gọn hơn cho tùy chọn 3: 'get {return _mC ?? (_mC = new MyClass); } ' – Mas

Trả lời

6

lựa chọn tốt nhất trừ khi bạn thực sự thể nhận được ngay với chỉ tạo ra một trường hợp mới cho mình: chỉ cung cấp nhà xây dựng mà thực hiện tất cả các giá trị cần thiết, và xác nhận họ vào thời điểm đó.

+0

Jon. Cảm ơn bạn đã bình luận. Trong tình huống đã kích hoạt điều này, có các thuộc tính ObservableCollection trong một Silverlight ViewModel tha có thể là EMPTY, nhưng không thể rỗng, vì chúng ta không bao giờ phá hủy cá thể ban đầu, chỉ cần thêm và xóa nội dung. TÔI CÓ THỂ lấy đi bằng cách làm của riêng tôi. –

+0

Tôi cũng tò mò về ý kiến ​​của bạn về việc sử dụng thuộc tính giá trị mặc định. –

+0

Thuộc tính giá trị mặc định chỉ được nhà thiết kế sử dụng, theo như tôi biết. Nó cũng có thể được sử dụng bởi serialization, vv - nhưng không phải bởi bình thường "chỉ cần tạo một thể hiện" mã. –

1

Trích tóm lược một câu hỏi tôi đã đăng cách đây vài ngày nhưng tôi nghĩ rằng nó có thể hữu ích để thực thi quy tắc mã và đảm bảo rằng Nulls một tái không được sử dụng mà bạn không muốn họ:

Microsoft vừa phát hành Code Contracts, một công cụ tích hợp với Visual Studio và cho phép bạn xác định hợp đồng cho mã .Net của bạn và nhận thời gian chạy kiểm tra thời gian biên dịch.

Xem video on Channel 9 cho biết cách sử dụng.

Đối với bây giờ nó là một add-on nhưng nó sẽ là một phần của cơ sở Class Library trong Net 4.0

0

Giả sử không có tác dụng phụ liên quan đến khi _mC được khởi tạo, (ví dụ, tất cả các khác là như nhau) , Tôi thích tùy chọn 3 như là tiết kiệm chi phí của một trường hợp bổ sung của MyClass trên heap trong trường hợp getter của MC không bao giờ được gọi.

2

Theo như tôi biết, có không thực tiễn tốt nhất được thiết lập ở đây vì một lý do đơn giản: mỗi tùy chọn của bạn có hồ sơ dấu chân hiệu suất/bộ nhớ khác nhau. Tùy chọn đầu tiên là thích hợp để tham chiếu đến một đối tượng mà bạn biết phải được khởi tạo trong một lớp mà bạn chắc chắn sẽ được sử dụng. Trung thực, mặc dù, tôi không bao giờ có cách tiếp cận này bởi vì tôi nghĩ rằng # 2 là chỉ thích hợp hơn; chỉ là một cảm giác rằng đây là những gì một nhà xây dựng là cho.

Tùy chọn cuối cùng phù hợp khi bạn là không phải chắc chắn liệu tùy chọn sẽ được sử dụng hay không. Nó cho phép bạn lấy tài nguyên chỉ khi cần thiết.

BTW, câu hỏi này là đúng "bên cạnh" với một số vấn đề khác như việc sử dụng thích hợp mẫu Singleton, sử dụng lớp trừu tượng hoặc giao diện cho đối tượng trì hoãn, v.v. để khám phá để có được cái nhìn sâu sắc hơn.

Cập nhật: Nó đánh tôi rằng có ít nhất một trường hợp khởi tạo một cá thể trong định nghĩa lớp là thích hợp (tùy chọn # 1) của bạn. Nếu trường hợp sẽ được tĩnh thì đây là nơi thích hợp chỉ - khởi tạo nó:

private static readonly DateTime firstClassDate = DateTime.Parse("1/1/2009 09:00:00 AM"); 

Tôi nghĩ về điều này khi tạo dòng trên mã trong một số xét nghiệm Đơn vị tôi đang viết ngày hôm nay (readonly được tùy chọn wrt điểm của tôi nhưng thích hợp trong trường hợp của tôi).

0

Tùy chọn (3) có lợi ích khi không phân bổ đối tượng cho đến khi cần, có thể dễ dàng điều chỉnh để trở thành đối tượng tải trễ (vì vậy khi tải đối tượng từ cơ sở dữ liệu) đối tượng con đầy đủ khi được yêu cầu)

0

tùy chọn 1 & 2 khác về mặt cú pháp nhưng về cơ bản là tương đương. Tùy chọn 3 là một phương pháp tiếp cận lười biếng mà tôi sử dụng rất nhất quán.
Tôi nghĩ rằng tất cả họ đều có cách sử dụng của họ, và nó phụ thuộc vào những gì bạn cần.

0

Trước hết tài sản không bao giờ bị rỗng hoặc không bao giờ bị vô hiệu khi khởi tạo? Tôi nghi ngờ bạn có nghĩa là trước đây trong trường hợp mã setter của bạn cần phải ngăn chặn null được thiết lập.

Mẫu cơ bản ở đây là trạng thái lớp bên ngoài không hợp lệ nếu trường lớp bên trong chưa được gán hợp lệ. Trong trường hợp đó, không chỉ setter bảo vệ trường từ null mà hàm khởi tạo nên đảm bảo nó khởi tạo đúng giá trị.

Mã của bạn ngụ ý rằng lớp bên ngoài có thể thể hiện lớp bên trong mà không cần nhập thêm từ mã tiêu thụ. Trong thế giới thực, lớp bên ngoài cần thêm thông tin từ bên ngoài để nhận một cá thể hiện có của lớp bên trong hoặc có đủ thông tin cho nó để lấy ra một.

+0

Cảm ơn nhận xét. Bạn đúng trong giả định của bạn. Tôi vừa ném một số mã mẫu và không bận tâm đến việc kiểm tra thiết lập. Tuy nhiên, trong sự kiện đó, điều đó sẽ rất quan trọng. –

0

Tùy chọn 1 là cách vani. Kể từ khi trở lại trong những ngày cũ, chúng tôi đã không có thuộc tính tự động thực hiện (Với {get; set;} sintax) để chúng là cách để xác định hành vi mặc định.

Khi tự động triển khai được giới thiệu, vì bạn không sử dụng trực tiếp trường lưu trữ giá trị mặc định (_mC), câu hỏi khá hay: "Tôi khởi tạo nó ở đâu?"

  • Lựa chọn 2 Được gọi háo hức tải: càng sớm càng lớp được tạo ra.
  • Tùy chọn 3 Được gọi là tải chậm: chỉ khi cần.

Tôi đã thấy rằng cách được chấp nhận phổ biến là Tùy chọn 2: tải mong muốn, nhưng tôi tin rằng đây chỉ là để giảm thiểu mã, hoàn toàn có thể chấp nhận được. Sự cố xảy ra khi bạn bắt đầu có nhiều hàm tạo với nhiều chữ ký và bạn kết thúc trỏ tất cả chúng đến phương thức khởi tạo void void() của một số loại.

Tôi đặc biệt thích Tùy chọn 3, vì nó vừa khai báo nhiều hơn cho mỗi trường/thuộc tính và nó được tối ưu hóa bộ nhớ. Hãy xem EntityFramework với các hương vị khác nhau: Code-First hoặc Database-first và bạn sẽ thấy cách xây dựng trong các thuộc tính nó sử dụng bộ nạp mong muốn trong khi các thuộc tính điều hướng nó ưu tiên (theo mặc định, có thể được tùy chỉnh) bộ nạp.

Ngoài ra, hãy tính đến những gì đang xảy ra trong trình tải này. Trong Entity Framework, điều đó có nghĩa là mỗi khi bạn khởi tạo nó sẽ thực hiện một chuyến đi tới Database và truy vấn một phần của nó. Bạn có thể bị DBA của bạn nhanh chóng có nhiều phiên đồng thời và có thể tập trung một số giao dịch trong các tải trọng đơn, do đó một số dây lại để làm trình tải mong muốn có thể phát ... mặc dù bạn sẽ kết thúc truy vấn một lượng lớn và làm chậm UX của bạn.

Trong Code-First bạn sẽ nhìn thấy ví dụ sau:

public class Blog 
{ 
    public int BlogId { get; set; } 
    public string Name { get; set; } 
    public string Url { get; set; } 
    public string Tags { get; set; } 

    public virtual ICollection<Post> Posts { get; set; } 
} 

Ở phía trên, bài viết thu thập được khai báo là ảo, vì nó sẽ được sửa đổi trong thời gian chạy tùy thuộc vào thiết lập của bạn. Nếu bạn thiết lập nó để tải háo hức, nó sẽ làm điều đó như Lựa chọn 2, trong khi đó nếu bạn đặt nó là lười biếng, nó sẽ được sửa đổi tương tự như Lựa chọn 3

Hy vọng rằng sẽ là hữu ích

Các vấn đề liên quan