2013-04-17 37 views
18

Hầu hết (nếu không phải tất cả) các khung POCO thực thể của tôi có các chức năng ảo. Tôi cần các chức năng này để được ảo để các thực thể có thể được tải lười biếng.Làm thế nào để tránh gọi hàm ảo trong hàm tạo?

Nếu tôi khởi tạo Accommodations trong hàm tạo thì tôi sẽ gọi hàm ảo trong hàm tạo, đó là thực hành không tốt.

Nhưng làm cách nào tôi có thể khởi tạo Accommodations nếu không có trong hàm tạo?

public class Venue 
{ 
    public Venue() 
    { 
     Accommodations = new HashSet<Accommodation>(); 
    } 

    public virtual ICollection<Accommodation> Accommodations { get; set; } 
} 
+1

điểm tải lười biếng là _not_ để khởi tạo nó ở tất cả, cho đến khi lần dùng đầu tiên. –

+0

@JohnWillemse Nếu tôi để cho nó null tôi sẽ nhận được ngoại lệ null trong quan điểm của tôi. –

+0

Không, bạn thử nghiệm cho null và khởi tạo nó khi cần thiết. Xem câu trả lời của Willem Duncan dưới đây để biết cách sử dụng. Có lẽ chúng ta đang bối rối các hình mẫu khác nhau ở đây, theo nhận xét của Daniel về cùng một câu trả lời. –

Trả lời

12
public class Venue 
{ 
    private accommodations_ = new HashSet<Accommodation>(); 

    public Venue() { } 

    public virtual ICollection<Accommodation> Accommodations 
    { 
     get { return accommodations_; } 
     set { accommodations_ = value; } 
    } 
} 
+3

Quy ước đặt tên lạ là gì? Bạn thường đặt dấu gạch dưới ở phía trước. –

+1

@DanielHilgarth, tôi sẽ không gọi nó là một quy ước chút nào - chỉ là một thói quen (có thể là xấu) của tôi mà tôi thực sự cần phải thay đổi;) –

+0

EF không giống như hàng đầu gạch dưới. – Casey

2

Với tải lười biếng, bạn thậm chí không khởi tạo Accommodations cho đến khi nó lần đầu tiên truy cập, vì vậy hãy để nó null.

Bạn có thể quấn như sau để làm cho nó automaticly khởi bản thân:

private ICollection<Accommodation> _accommodations; 

public virtual ICollection<Accommodation> Accommodations { 
    get { 
     if (_accommodations == null) 
     { 
      // Initialize or load data here. 
      _accommodations = new HashSet<Accommodation>(); 
     } 
     return _accomodations; 
    } 
    set { 
     _accommodations = value; 
    } 
} 

Hãy chắc chắn để đọc các bình luận dưới đây liên quan đến giải pháp này!

+7

Anh ấy đang nói về việc tải chậm trong ngữ cảnh của ORM. ORM sẽ chăm sóc tất cả những điều này cho bạn, vì vậy câu trả lời của bạn đã bỏ lỡ điểm. Ngoài ra, vui lòng xem [câu trả lời này] (http://stackoverflow.com/questions/14774008/good-or-bad-practice-initializing-objects-in-getter/14774042#14774042) về thực tiễn bạn hiển thị ở đây. –

+0

Điểm tốt, tìm hiểu điều gì đó mỗi ngày, đã thêm một con trỏ vào câu trả lời. –

+0

Cảm ơn bạn đã liên kết Daniel. –

14

Tùy chọn khác là đánh dấu người đặt là riêng tư. Điều này sẽ loại bỏ vấn đề gọi các thành viên ảo trong hàm tạo.

Khi bạn làm điều đó, bạn cần cung cấp các cách thức cho người gọi (ngoài EF) để đặt thuộc tính đó khi cần thiết theo thiết kế của bạn. Bạn có thể sử dụng một constructor quá tải để truyền vào một danh sách các tùy chọn, hoặc tùy chọn đóng gói bộ sưu tập của bạn (Domain driven design) và sử dụng các phương thức để thêm/xóa các mục (lưu ý, với EF này trở thành "hackish", vì nó thiếu hỗ trợ cho đóng gói đầy đủ bộ sưu tập, không giống với NHibernate):

public class Venue 
{ 
    public Venue() 
    { 
     Accommodations = new HashSet<Accommodation>(); 
    } 

    public Venue(ICollection<Accommodation> accommodations) 
    { 
     Accommodations = new List<Accommodation>(accommodations); 
    } 

    public virtual ICollection<Accommodation> Accommodations { get; private set; } 
} 
+2

Chính xác những gì tôi cần. Hài hước như thế nào câu hỏi này là hơn một năm tuổi, nhưng bạn đã đăng câu trả lời này chỉ 4 giờ trước khi tôi đi tìm nó! – Xcelled194

0

với sự khởi tạo mặc định C# 6.0, bạn có thể đơn giản mà không cần sử dụng các biến tin:

public class Venue 
{ 
    public virtual ICollection<Accommodation> Accommodations {get; set; } = new HashSet<Accommodation>(); 
} 
Các vấn đề liên quan