Třídy (F#)

Třídy jsou typy, které představují objekty, které mohou mít vlastnosti, metody a události.

Syntaxe

// Class definition:
type [access-modifier] type-name [type-params] [access-modifier] ( parameter-list ) [ as identifier ] =
[ class ]
[ inherit base-type-name(base-constructor-args) ]
[ let-bindings ]
[ do-bindings ]
member-list
...
[ end ]
// Mutually recursive class definitions:
type [access-modifier] type-name1 ...
and [access-modifier] type-name2 ...
...

Poznámky

Třídy představují základní popis typů objektů .NET; třída je primární koncept typu, který podporuje objektově orientované programování v jazyce F#.

V předchozí syntaxi type-name je libovolný platný identifikátor. Popisuje type-params volitelné parametry obecného typu. Skládá se z názvů parametrů typu a omezení uzavřených v hranatých závorkách (< a >). Další informace naleznete v tématu Obecné typy a omezení. Popisuje parameter-list parametry konstruktoru. První modifikátor přístupu se týká typu; druhý se týká primárního konstruktoru. V obou případech je publicvýchozí hodnota .

Základní třídu třídy zadáte pomocí klíčového inherit slova. Argumenty je nutné zadat v závorkách pro konstruktor základní třídy.

Deklarujete pole nebo hodnoty funkcí, které jsou pro třídu místní, pomocí let vazeb a musíte dodržovat obecná pravidla pro let vazby. Oddíl do-bindings obsahuje kód, který se má provést při konstrukci objektu.

Skládá member-list se z dalších konstruktorů, deklarací instance a statické metody, deklarací rozhraní, abstraktních vazeb a deklarací vlastností a událostí. Jsou popsány v části Členové.

Používá identifier se s volitelným as klíčovým slovem název proměnné instance nebo identifikátoru sebe, který lze použít v definici typu k odkazování na instanci typu. Další informace najdete v části Self Identifiers dále v tomto tématu.

Klíčová slova class a end označující začátek a konec definice jsou volitelná.

Vzájemně rekurzivní typy, což jsou typy, které vzájemně odkazují, jsou spojeny s klíčovým slovem and stejně jako vzájemně rekurzivní funkce jsou. Příklad najdete v části Vzájemně se rekurzivní typy.

Konstruktory

Konstruktor je kód, který vytvoří instanci typu třídy. Konstruktory pro třídy fungují v jazyce F# trochu jinak než v jiných jazycích .NET. Ve třídě jazyka F# je vždy primární konstruktor, jehož argumenty jsou popsány za parameter-list názvem typu a jehož tělo se skládá z let vazeb (a let rec) na začátku deklarace třídy a do vazeb, které následují. Argumenty primárního konstruktoru jsou v oboru v rámci deklarace třídy.

Další konstruktory můžete přidat pomocí klíčového new slova pro přidání člena následujícím způsobem:

new(argument-list) = constructor-body

Tělo nového konstruktoru musí vyvolat primární konstruktor zadaný v horní části deklarace třídy.

Následující příklad ukazuje tento koncept. V následujícím kódu MyClass má dva konstruktory, primární konstruktor, který přebírá dva argumenty a jiný konstruktor, který nepřijímá žádné argumenty.

type MyClass1(x: int, y: int) =
    do printfn "%d %d" x y
    new() = MyClass1(0, 0)

let a do Bindings

do Vazby let v definici třídy tvoří tělo konstruktoru primární třídy, a proto se spouští při každém vytvoření instance třídy. Pokud je vazbou let funkce, zkompiluje se do člena. let Pokud je vazba hodnota, která se nepoužívá v žádné funkci nebo členu, je zkompilována do proměnné, která je místní pro konstruktor. V opačném případě se zkompiluje do pole třídy. Následující do výrazy jsou zkompilovány do primárního konstruktoru a spouští inicializační kód pro každou instanci. Vzhledem k tomu, že všechny další konstruktory vždy volají primární konstruktor, let vazby a do vazby vždy spustí bez ohledu na to, který konstruktor je volána.

K polím vytvořeným vazbami let lze přistupovat v rámci metod a vlastností třídy. Nelze k nim ale přistupovat ze statických metod, a to ani v případě, že statické metody jako parametr přebírají proměnnou instance. K nim nelze získat přístup pomocí identifikátoru sebe sama, pokud existuje.

Identifikátory sebe sama

Identifikátor sebe sama je název, který představuje aktuální instanci. Identifikátory sebe se podobají klíčovému slovu this v jazyce C# nebo C++ nebo Me v jazyce Visual Basic. Identifikátor sebeobsadu můžete definovat dvěma různými způsoby v závislosti na tom, jestli má být identifikátor sebeobsadu v oboru pro celou definici třídy, nebo jen pro jednotlivé metody.

Chcete-li definovat identifikátor sebe pro celou třídu, použijte as klíčové slovo za závěrečnou závorkou seznamu parametrů konstruktoru a zadejte název identifikátoru.

Pokud chcete definovat identifikátor sebe sama pro jen jednu metodu, zadejte identifikátor sebe v deklaraci člena těsně před názvem metody a tečkou (.) jako oddělovač.

Následující příklad kódu znázorňuje dva způsoby vytvoření identifikátoru sebe sama. Na prvním řádku as se klíčové slovo používá k definování identifikátoru sebe sama. V pátém řádku se identifikátor this používá k definování vlastního identifikátoru, jehož obor je omezen na metodu PrintMessage.

type MyClass2(dataIn) as self =
    let data = dataIn
    do
        self.PrintMessage()
    member this.PrintMessage() =
        printf "Creating MyClass2 with Data %d" data

Na rozdíl od jiných jazyků rozhraní .NET můžete vlastní identifikátor pojmenovat, ale chcete; nejste omezeni na názvy, jako selfjsou , Menebo this.

Identifikátor sebe, který je deklarován pomocí klíčového as slova, není inicializován až po základní konstruktor. Proto při použití před nebo uvnitř základního konstruktoru bude System.InvalidOperationException: The initialization of an object or value resulted in an object or value being accessed recursively before it was fully initialized. vyvolán během modulu runtime. Identifikátor sebe sama můžete použít volně za základním konstruktorem, například ve let vazbách nebo do vazbách.

Parametry obecného typu

Parametry obecného typu jsou zadány v hranatých závorkách (< a >), ve formě jednoduché uvozovky následované identifikátorem. Více parametrů obecného typu je odděleno čárkami. Parametr obecného typu je v oboru v celé deklaraci. Následující příklad kódu ukazuje, jak zadat parametry obecného typu.

type MyGenericClass<'a>(x: 'a) =
    do printfn "%A" x

Argumenty typu se odvozují při použití typu. V následujícím kódu je odvozený typ posloupnosti řazených kolekcí členů.

let g1 = MyGenericClass(seq { for i in 1..10 -> (i, i * i) })

Určení dědičnosti

Klauzule inherit identifikuje přímou základní třídu, pokud existuje. V jazyce F# je povolena pouze jedna přímá základní třída. Rozhraní, která implementuje třída, nejsou považována za základní třídy. Rozhraní jsou popsána v tématu Rozhraní .

K metodám a vlastnostem základní třídy můžete přistupovat z odvozené třídy pomocí klíčového slova base jazyka jako identifikátoru, za kterým následuje tečka (.) a název člena.

Další informace najdete v tématu Dědičnost.

Oddíl Členové

V této části můžete definovat statické nebo instance metody, vlastnosti, implementace rozhraní, abstraktní členy, deklarace událostí a další konstruktory. V této části nelze zobrazit vazby a provádět vazby. Vzhledem k tomu, že kromě tříd je možné přidávat členy do různých typů jazyka F#, probírají se v samostatném tématu Členové.

Vzájemně se rekurzivní typy

Když definujete typy, které vzájemně odkazují cyklickým způsobem, zadáváte dohromady definice typů pomocí klíčového and slova. Klíčové and slovo nahradí type klíčové slovo u všech kromě první definice následujícím způsobem.

open System.IO

type Folder(pathIn: string) =
    let path = pathIn
    let filenameArray: string array = Directory.GetFiles(path)
    member this.FileArray = Array.map (fun elem -> new File(elem, this)) filenameArray

and File(filename: string, containingFolder: Folder) =
    member this.Name = filename
    member this.ContainingFolder = containingFolder

let folder1 = new Folder(".")

for file in folder1.FileArray do
    printfn "%s" file.Name

Výstup je seznam všech souborů v aktuálním adresáři.

Kdy použít třídy, sjednocení, záznamy a struktury

Vzhledem k různým typům, ze kterých si můžete vybrat, musíte mít dobrou představu o tom, jaký typ je určený k výběru vhodného typu pro konkrétní situaci. Třídy jsou navržené pro použití v kontextech objektově orientovaného programování. Objektově orientované programování je dominantní paradigma používané v aplikacích, které jsou napsané pro rozhraní .NET Framework. Pokud váš kód jazyka F# musí úzce spolupracovat s rozhraním .NET Framework nebo jinou objektově orientované knihovnou, a zejména v případě, že je nutné rozšířit ze systému objektově orientovaného typu, jako je knihovna uživatelského rozhraní, jsou třídy pravděpodobně vhodné.

Pokud úzce nespolupracuje s objektově orientovaným kódem, nebo pokud píšete kód, který je samostatně obsažený, a proto je chráněn před častým interakcí s objektově orientovaným kódem, měli byste zvážit použití kombinace tříd, záznamů a diskriminovaných sjednocení. Jedinou, dobře promyšlenou diskriminovanou sjednocení spolu s odpovídajícím kódem vzorů lze často použít jako jednodušší alternativu k hierarchii objektů. Další informace o diskriminovaných svazech naleznete v tématu Diskriminované sjednocení.

Záznamy mají výhodu, že jsou jednodušší než třídy, ale záznamy nejsou vhodné, pokud požadavky typu překročí to, co je možné dosáhnout s jejich jednoduchostí. Záznamy jsou v podstatě jednoduché agregace hodnot bez samostatných konstruktorů, které mohou provádět vlastní akce bez skrytých polí a bez dědičnosti nebo implementace rozhraní. I když je možné do záznamů přidat členy, jako jsou vlastnosti a metody, aby jejich chování bylo složitější, pole uložená v záznamu jsou stále jednoduchou agregací hodnot. Další informace o záznamech naleznete v tématu Záznamy.

Struktury jsou také užitečné pro malé agregace dat, ale liší se od tříd a záznamů v tom, že jsou typy hodnot .NET. Třídy a záznamy jsou referenční typy .NET. Sémantika typů hodnot a odkazových typů se liší v tom, že typy hodnot se předávají podle hodnoty. To znamená, že se zkopírují bit pro bit, když jsou předány jako parametr nebo vráceny z funkce. Jsou také uloženy v zásobníku nebo, pokud se používají jako pole, vložené do nadřazeného objektu namísto uložení ve vlastním samostatném umístění v haldě. Proto jsou struktury vhodné pro často přístupná data, když je problém s režií při přístupu k haldě. Další informace o strukturách naleznete v tématu Struktury.

Viz také