2016-06-24 25 views
9

Tôi muốn một số cách để xác định các hồ sơ liên quan. Ví dụ,Ghi lại các biến thể trong F #

type Thing  = { field1: string; field2: float } 
type ThingRecord = { field1: string; field2: float; id: int; created: DateTime } 

hoặc

type UserProfile = { username: string; name: string; address: string } 
type NewUserReq = { username: string; name: string; address: string; password: string } 
type UserRecord = { username: string; name: string; address: string; encryptedPwd: string; salt: string } 

cùng với một cách để chuyển đổi từ một đến khác, mà không cần phải viết rất nhiều soạn sẵn. Ngay cả ví dụ đầu tiên đầy đủ sẽ là:

type Thing = 
    { field1: string 
    field2: float } 
    with 
    member this.toThingRecord(id, created) = 
     { field1 = this.field1 
     field2 = this.field2 
     id = id 
     created = created } : ThingRecord 
and ThingRecord = 
    { field1: string 
    field2: float 
    id: int 
    created: DateTime } 
    with 
    member this.toThing() = 
     { field1 = this.field1 
     field2 = this.field2 } : Thing 

Khi bạn nhận được tối đa field10 v.v., nó trở thành trách nhiệm pháp lý.

Tôi hiện đang thực hiện việc này theo cách không an toàn (và chậm) bằng cách sử dụng phản chiếu.

Tôi đã thêm một yêu cầu cho cú pháp with để được mở rộng để ghi lại các định nghĩa trên uservoice, điều này sẽ đáp ứng nhu cầu này.

Nhưng có lẽ có một cách an toàn để thực hiện việc này không? Có thể với các nhà cung cấp loại?

Trả lời

4

Vâng, đó là một nứt nẻ trong áo giáp khác sáng bóng 's F #. Tôi không cảm thấy có một giải pháp phổ quát ở đó để dễ dàng kế thừa hoặc mở rộng một bản ghi. Không nghi ngờ gì là có một sự thèm ăn cho một - Tôi đã đếm hơn một chục bài gửi kinh nghiệm ủng hộ những cải tiến dọc theo những dòng này - đây là một số hàng đầu, hãy bỏ phiếu: 1, 2, 3, 4, 5.

Chắc chắn, có những việc bạn có thể làm để khắc phục sự cố và tùy thuộc vào tình huống của bạn, chúng có thể hoạt động tốt cho bạn. Nhưng cuối cùng - chúng cách giải quyết và có điều gì đó bạn phải hy sinh:

  • Tốc độ và loại an toàn khi sử dụng phản chiếu,
  • Ngắn gọn khi bạn đi kiểu cách an toàn và có hồ sơ chính thức với các chức năng chuyển đổi giữa chúng,
  • Tất cả tính tốt đẹp cú pháp và ngữ nghĩa mà bản ghi cung cấp cho bạn miễn phí khi bạn quyết định quay trở lại các lớp .NET thuần túy và kế thừa.

Nhà cung cấp loại sẽ không cắt vì chúng không thực sự là công cụ tốt để lập trình meta. Đó không phải là những gì chúng được thiết kế. Nếu bạn cố gắng sử dụng chúng theo cách đó, bạn bị ràng buộc để đạt một số giới hạn.

Đối với một, bạn chỉ có thể cung cấp các loại dựa trên thông tin bên ngoài. Điều này có nghĩa rằng trong khi bạn có thể có một nhà cung cấp loại sẽ kéo theo các loại từ a.NET lắp ráp thông qua sự phản ánh và cung cấp một số loại có nguồn gốc dựa trên đó, bạn không thể "introspect" vào lắp ráp bạn đang xây dựng. Vì vậy, không có cách nào để bắt nguồn từ một kiểu được định nghĩa trước đó trong cùng một assembly.

Tôi đoán bạn có thể làm việc xung quanh điều đó bằng cách cấu trúc các dự án của bạn xung quanh nhà cung cấp loại, nhưng điều đó nghe có vẻ bối rối. Và thậm chí sau đó, bạn không thể cung cấp các loại bản ghi anyway yet, vì vậy tốt nhất bạn có thể làm là các lớp .NET đơn giản.

Để biết trường hợp sử dụng cụ thể hơn về việc cung cấp một số loại ánh xạ ORM cho cơ sở dữ liệu - tôi tưởng tượng bạn có thể sử dụng các nhà cung cấp kiểu tốt. Chỉ cần không phải là một cơ sở lập trình metaprogram chung.

+0

Rất tiếc, tôi đã lên kế hoạch thực hiện việc này vào tuần tới nếu không có giải pháp hiện có, nhưng thực tế (đáng ngạc nhiên) rằng các nhà cung cấp loại không hỗ trợ các loại bản ghi phần nào giết chết ý tưởng đó. –

+0

Vâng, nếu bạn có hai tuần, bạn luôn có thể bắt đầu bằng cách làm cho nhà cung cấp loại phát ra các loại bản ghi;) – scrwtp

+0

Hoàn toàn sẵn sàng, nhưng hãy tiết kiệm cho tôi một vài ngày: tôi sẽ bắt đầu từ đâu? –

1

Tại sao bạn không làm cho chúng lồng nhau hơn, như sau?

type Thing  = { Field1: string; Field2: float } 
type ThingRecord = { Thing : Thing; Id: int; Created: DateTime } 

hoặc

type UserProfile = { Username: string; Name: string; Address: string } 
type NewUserReq = { UserProfile: UserProfile; Password: string } 
type UserRecord = { UserProfile: UserProfile; EncryptedPwd: string; Salt: string } 

chức năng chuyển đổi là tầm thường:

let toThingRecord id created thing = { Thing = thing; Id = id; Created = created } 
let toThing thingRecord = thingRecord.Thing 

Cách sử dụng:

> let tr = { Field1 = "Foo"; Field2 = 42. } |> toThingRecord 1337 (DateTime (2016, 6, 24));; 

val tr : ThingRecord = {Thing = {Field1 = "Foo"; 
           Field2 = 42.0;}; 
         Id = 1337; 
         Created = 24.06.2016 00:00:00;} 
> tr |> toThing;; 
val it : Thing = {Field1 = "Foo"; 
        Field2 = 42.0;} 
+0

Lý tưởng nhất, có, nhưng cơ sở dữ liệu không thích điều đó, và (thậm chí lý tưởng) đôi khi nó cảm thấy lạ khi có cấu trúc lồng nhau khi bạn thực sự đại diện cho một vật bằng phẳng. –

+0

Và đôi khi có các công cụ cắt ngang làm cho tổ không khởi động. ví dụ. khi lồng ghép, 'WithId >' sẽ khác với '>'; nhưng tôi muốn 'thing.withId (id) .withTimestamp (ts)' tương đương với 'thing.withTimestamp (ts) .withId (id)'. –

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