2016-06-24 3 views
9

관련 레코드를 정의하는 방법이 필요합니다. 예를 들어,F #의 레코드 변형

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

또는 너무 많은 보일러를 쓸 필요없이, 다른 하나에서 변환하는 방법과 함께

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 } 

. 전체에서 심지어 첫 번째 예는 다음과 같습니다

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 

당신이 field10 등까지 얻을, 그것은 책임으로 가져옵니다.

저는 현재 리플렉션을 사용하여 안전하지 않은 (그리고 느린) 방식으로이 작업을 수행하고 있습니다.

이 요구를 충족시킬 uservoice의 정의를 기록하기 위해 with 구문을 확장하도록 요청을 추가했습니다.

하지만 이미 이것을 할 수있는 형식 안전 방법이 있습니까? 어쩌면 유형 공급자가 있습니까?

답변

4

예, F #의 다른 빛나는 갑옷의 갈라진 틈이있다. 쉽게 상속하거나 확장 할 수있는 보편적 인 해결책이 없다고 생각합니다. 의심의 여지가 하나에 대한 식욕이 있습니다 - 나는이 라인을 따라 개선을 옹호하는 12 개의 사용자 음성 신청서를 세었습니다. 여기에 몇 가지 주요한 것들이 있습니다 : 1, 2, 3, 4, 5.

확실히이 문제를 해결하기 위해 할 수있는 일이 있으며, 시나리오에 따라 적절하게 작동 할 수 있습니다. 그러나 궁극적으로 - 그들이 해결 방법을이야 그리고 당신은 희생해야 뭔가가있다 :

  • 속도와 유형의 안전 반사를 사용하여,
  • 간결은 유형 안전한 방법을 가서 변환 함수 사이에 본격적인 기록이 그 (것)들
  • 당신이 보통 .NET 종류 및 상속으로 넘어지는 것을 결정할 때 기록이 자유롭게주는 모든 통어론과 의미 상 선량.

유형 제공자는 메타 프로그래밍을위한 좋은 도구가 아니기 때문에 유형을 잘라 내지 않습니다. 그것은 그들이 설계된 것이 아닙니다. 그런 식으로 사용하려고하면 몇 가지 제한이 있습니다.

하나의 경우 외부 정보를 기반으로하는 유형 만 제공 할 수 있습니다. 이것은 타입 제공자를 가질 수있는 반면에 타입 제공자를 가질 수 있다는 것을 의미합니다.NET 어셈블리를 리플렉션하고이를 기반으로 파생 된 유형을 제공하면 빌드중인 어셈블리를 "인트로 스펙 트"할 수 없습니다. 동일한 어셈블리에서 이전에 정의 된 유형에서 파생 할 방법이 없습니다.

나는 당신이 타입 제공자 주위에 당신의 프로젝트를 구조화함으로써 해결할 수 있다고 생각하지만, 그것은 clunky라고 들린다. 그리고 그 다음에도 어쨌든 yet 레코드 유형을 제공 할 수 없으므로 최선의 .NET 클래스가 될 수 있습니다.

데이터베이스에 대해 일종의 ORM 매핑을 제공하는보다 구체적인 사용 사례는 유형 공급자를 잘 사용할 수 있다고 생각합니다. 일반적인 메타 프로그래밍 기능이 아닙니다.

+0

Bummer, 아무도 기존 솔루션을 갖고 있지 않다면 다음 주에이 작업을 계획하고 있었지만 형식 공급자가 레코드 유형을 지원하지 않는다는 사실이 다소 그 아이디어를 없앴습니다. –

+0

글쎄요, 2 주일이면 타입 제공자가 레코드 유형을 생성하도록 항상 시작할 수 있습니다;) – scrwtp

+0

완전히 기꺼이하지만 며칠을 절약 할 수 있습니다. –

1

다음과 같이 중첩시키지 않는 이유는 무엇입니까?

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

또는

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

변환 기능은 사소한 :

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

사용법 :

> 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

이상적으로는 그렇지만 데이터베이스는 그 점을 좋아하지 않으며 (심지어 이상적으로) 때로는 평평한 것을 표현할 때 중첩 된 구조를 갖는 것이 이상하게 느껴지기도합니다. –

+0

때로는 네스터를 비 스타터로 만드는 크로스 커팅 도구가 있습니다. 예 : 중첩 할 때 WithId >은'>'과 다를 것입니다. 하지만 나는'thing.withId (id) .withTimestamp (ts)'가'thing.withTimestamp (ts) .withId (id)'와 같을 것을 원합니다. –