2012-02-08 40 views
6

Vì vậy, khi bao giờ im tạo một số thuộc tính trong mã F # của tôi, vì F # không hỗ trợ các thuộc tính tự động, theo như tôi biết. Tôi phải tạo ra các lĩnh vực sao lưu và khởi tạo chúng để null, mà không có vẻ đúng trong điều khoản lập trình chức năng. Ví dụ:Thiết kế thuộc tính F #

 

let mutable albums : DbSet = null 
let mutable genres : DbSet = null

member x.Albums with get() = albums and set(value) = albums <- value member x.Genres with get() = genres and set (value) = genres <- value

Có cách nào tốt hơn để làm việc này không? Rất cám ơn các đề xuất của bạn.

+1

Một điều - ngoài câu trả lời tuyệt vời của Pad và TomasPetricek: nếu bạn thực sự cố gắng "hoạt động" thì tôi sẽ kiểm tra giả định rằng bạn cần lớp học hoặc lớp học- như cấu trúc ở nơi đầu tiên. Thuộc tính tự động vi phạm ẩn thông tin tốt bằng cách phơi bày bên trong của một lớp nhất định cho phần còn lại của ứng dụng. Nếu bạn cần phần bên trong của một lớp tiếp xúc với phần còn lại của ứng dụng thì có thể bạn không cần lớp học ngay từ đầu. Tôi đoán tôi đang nói nếu bạn thực sự muốn suy nghĩ về mặt chức năng để loại bỏ ý tưởng rằng mọi thứ phải ở trong một lớp học. –

+0

Oh và một điều nữa - với những gì bạn đang làm việc, bạn có thể thấy bài đăng trên blog này hữu ích: http://bugsquash.blogspot.com/2011/11/lenses-in-f.html –

Trả lời

10

F # không hỗ trợ tính tự động khi bạn cần một mutable bất động sản, nhưng nó hỗ trợ một cú pháp nhẹ khi bạn cần chỉ là một tài sản readonly. Nếu bạn đang viết một số mã chức năng, sau đó sử dụng readonly tính thực sự có thể thích hợp hơn:

type Music(genres : DbSet, albums : DbSet) = 
    member x.Albums = albums 
    member x.Genres = genres 

Đây thực chất là giống như hồ sơ đề nghị của pad, nhưng nó có thể thích hợp hơn nếu bạn muốn có kiểm soát tốt hơn cách các kiểu nhìn (và cách chúng xuất hiện trong C# hoặc cho ràng buộc dữ liệu).

Nếu DbSet là loại có thể thay đổi, thì có thể bạn chỉ cần sử dụng loại trên và khởi tạo chỉ một lần (bạn vẫn có thể sửa đổi giá trị DbSet). Nếu bạn muốn thay đổi giá trị DbSet, bạn có thể thêm một phương thức trả về một đối tượng nhân bản:

member x.WithAlbums(newAlbums) = 
    Music(genres, newAlbums) 

Sử dụng null hoặc Unchecked.defaultOf<_> trong F # được coi là một thực tế rất xấu và bạn nên luôn luôn cố gắng tạo ra đối tượng hoàn toàn initlized. Nếu giá trị có thể bị thiếu, bạn có thể sử dụng loại option để đại diện cho điều đó, nhưng sau đó bạn phải luôn viết xử lý cho giá trị bị thiếu, để làm cho chương trình của bạn an toàn.

+0

mà chính xác những gì tôi nghĩ bằng cách sử dụng null không thể được coi là một thực hành tốt đẹp trong một ngôn ngữ trong đó có loại tùy chọn rõ ràng chỉ cho mục đích này. Cảm ơn lời đề nghị của bạn. – netmatrix01

+0

WPF có chấp nhận các loại tùy chọn có lợi cho các giá trị rỗng không? – Maslow

5

Trừ khi bạn đang làm điều gì đó phức tạp, tôi khuyên bạn nên sử dụng hồ sơ thay vì các lớp học. Về cơ bản, họ là lớp học với tính năng bổ sung: không thay đổi, bình đẳng về cơ cấu, mô hình phù hợp, vv:

type Playlists = { 
    Albums: DbSet; 
    Genres: DbSet 
    } 

Bạn có thể nhận các lĩnh vực kỷ lục của một cách dễ dàng:

let p = {Albums = ...; Genres = ...} 
let albums = p.Albums 
let genres = p.Genres 

Trong hồ sơ lĩnh vực mặc định là không thay đổi; bạn có thể khai báo các trường có thể thay đổi trong các bản ghi, nhưng nó được coi là một thực hành không tốt. Mặc dù bạn không thể đặt thuộc tính, bạn có thể tạo bản ghi mới từ một tệp cũ. Mặc định tính bất biến là bình thường không phải là một vấn đề, hơn nữa nó làm cho mã chức năng hơn và dễ dàng hơn để suy luận về:

let p = {Albums = a; Genres = g} 

    // Create new records by updating one field 
    let p1 = {p with Albums = a1} 
    let p2 = {p with Genres = g2} 

Nếu bạn nhấn mạnh để tạo ra các lớp học, sử dụng một constructor với các thông số rõ ràng được đề nghị:

type Playlists(a: DbSet, g: DbSet) = 
    let mutable albums = a 
    let mutable genres = g 
    // ... 

Khi một constructor mặc định là cần thiết, bạn có thể sử dụng Unchecked.default<'T> cho các lĩnh vực phi nullable, hoặc tốt hơn sử dụng nhà thầu mặc định của họ:

// Set fields using dump values 
let mutable albums = new DbSet() 
let mutable genres = new DbSet() 

Nhưng hãy chắc chắn rằng bạn thiết lập các trường đó trước khi sử dụng chúng.

+0

Lưu ý rằng bạn có thể cũng làm cho các trường của một bản ghi có thể thay đổi theo cách tầm thường. Các bản ghi cũng có một số nhược điểm, ví dụ, bạn phải thiết lập rõ ràng giá trị của tất cả các trường của nó để xây dựng một đối tượng. Một bất lợi khác là các loại bản ghi không thể kế thừa và không thể bắt nguồn từ đó. – ShdNx

+1

Đúng là các bản ghi có thể có các trường có thể thay đổi. Nhưng tôi coi đó là một thiết kế tồi. Khi bạn đi theo cách đó, các lớp học nên được ưa thích hơn. – pad

+0

Cảm ơn Pad cho các đề xuất của bạn. Có lẽ tôi sẽ sử dụng hồ sơ nhưng trong trường hợp của tôi tôi nghĩ rằng im quan tâm hơn đến một tài sản. Nhưng tôi sẽ suy nghĩ lại về đề xuất của bạn và xem liệu tôi có thể thiết kế loại của tôi dưới dạng Bản ghi hay không. – netmatrix01

5

FYI - các thuộc tính tự động được lên kế hoạch cho F # 3.0. Xem số preview documentation [MSDN].Có vẻ như ví dụ của bạn sẽ trở thành:

type Music() = 
    member val Albums : DbSet = null with get, set 
    member val Genres : DbSet = null with get, set 
+0

dường như những điều này không được phép là private – Maslow

+0

'thành viên val GroupBox1: GroupBox = new GroupBox()' throws nói 'Thông tin bổ sung: Khởi tạo một đối tượng hoặc giá trị dẫn đến một đối tượng hoặc giá trị được truy cập đệ quy trước khi nó hoàn toàn initialized.' Hàm khởi tạo này dường như chạy sau khi lớp đang giữ hàm tạo của thuộc tính tự động. – Maslow

+0

Chắc chắn họ là: 'thành viên val tư nhân ...' – Daniel

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