F # ma funkcję o nazwie "Type extension", która daje programistom możliwość rozszerzenia istniejących typów. Dostępne są dwa typy rozszerzeń: wewnętrzne rozszerzenie i opcjonalne rozszerzenie. Pierwszy jest podobny do typów częściowych w języku C#, a drugi jest podobny do rozszerzenia metody (ale mocniejszy).Rozszerzenia typów i widoczność członków w języku F #
Aby użyć rozszerzenia wewnętrznego, należy umieścić dwie deklaracje w tym samym pliku. W tym przypadku kompilator połączy dwie definicje w jeden ostateczny typ (tj. Są to dwie "części" jednego typu).
Kwestia jest taka, że te dwa rodzaje ma inne zasady dostępu dla różnych członków i wartości:
// SampleType.fs
// "Main" declaration
type SampleType(a: int) =
let f1 = 42
let func() = 42
[<DefaultValue>]
val mutable f2: int
member private x.f3 = 42
static member private f4 = 42
member private this.someMethod() =
// "Main" declaration has access to all values (a, f1 and func())
// as well as to all members (f2, f3, f4)
printf "a: %d, f1: %d, f2: %d, f3: %d, f4: %d, func(): %d"
a f1 this.f2 this.f3 SampleType.f4 (func())
// "Partial" declaration
type SampleType with
member private this.anotherMethod() =
// But "partial" declaration has no access to values (a, f1 and func())
// and following two lines won't compile
//printf "a: %d" a
//printf "f1: %d" f1
//printf "func(): %d" (func())
// But has access to private members (f2, f3 and f4)
printf "f2: %d, f3: %d, f4: %d"
this.f2 this.f3 SampleType.f4
czytam F specyfikację #, ale nie znaleźliśmy żadnych pomysłów, dlaczego F # kompilator różnicują deklaracji wartości i członka.
W 8.6.1.3 section o f # specyfikacji że „Funkcje i wartości określone definicje przykład są lexically zawężona (a tym samym pośrednio prywatny) do określonego obiektu.”. Częściowa deklaracja ma dostęp do wszystkich prywatnych członków (statycznych i instancji). Domyślam się, że autorzy specyfikacji "zakresu leksykalnego" mają na myśli tylko "główną" deklarację, ale zachowanie to wydaje mi się dziwne.
Pytanie brzmi: czy to zachowanie jest zamierzone i jakie ma racjonalne uzasadnienie?
Dostałem twój punkt o podobieństwie między dwoma typami rozszerzeń typu. Ale zachowanie * wewnętrznych * i * opcjonalnych * rozszerzeń jest różne: opcjonalne rozszerzenia mogą uzyskiwać dostęp tylko do publicznej powierzchni rozszerzonego typu, ale wewnętrzne rozszerzenia nadal mają dostęp do prywatnych i chronionych członków rozszerzonego typu. Miały też inną semantyczną cechę, a nie tylko sposób ich kompilacji pod osłoną. –
@SergeyTeplyakov Hmm, to dobry punkt. Masz rację, że różnią się pod tym względem. Przypuszczam, że kluczową kwestią jest zatem definicja "zakresu leksykalnego" w tym kontekście (czego wyraźnie brakuje w specyfikacji F #). –
Dzięki, Tomas. Myślę, że masz rację co do zakresu leksykalnego. Chodzi mi o to, że częściowe typy w języku C# są dobrze znaną i szeroko stosowaną funkcją wsparcia projektantów. Ale z takim ograniczeniem nie możemy traktować wewnętrznego rozszerzenia jako w pełni funkcjonalnej deklaracji typu częściowego. A to oznacza, że nie możemy uzyskać wsparcia projektantów (dla WinForms i WPF), dopóki wewnętrzne rozszerzenia nie mają takich ograniczeń. –