Teilen über


Namespaces (F#)

Mit einem Namespace können Sie Code in Bereiche verwandter Funktionen organisieren, indem Sie einen Namen an eine Gruppierung von F#-Programmelementen anfügen können. Namespaces sind in der Regel Elemente der obersten Ebene in F#-Dateien.

Syntax

namespace [rec] [parent-namespaces.]identifier

Bemerkungen

Wenn Sie Code in einen Namespace einfügen möchten, muss die erste Deklaration in der Datei den Namespace deklarieren. Der Inhalt der gesamten Datei wird dann Teil des Namespace, sofern keine andere Namespacedeklaration weiter in der Datei vorhanden ist. Wenn dies der Fall ist, wird der gesamte Code bis zur nächsten Namespacedeklaration als innerhalb des ersten Namespace betrachtet.

Namespaces dürfen keine Werte und Funktionen direkt enthalten. Stattdessen müssen Werte und Funktionen in Module enthalten sein, und Module sind in Namespaces enthalten. Namespaces können Typen und Module enthalten.

XML-Dokumentkommentare können über einem Namespace deklariert werden, werden jedoch ignoriert. Compilerdirektiven können auch über einem Namespace deklariert werden.

Namespaces können explizit mit dem Namespace-Schlüsselwort deklariert werden oder implizit beim Deklarieren eines Moduls. Um einen Namespace explizit zu deklarieren, verwenden Sie das Namespace-Schlüsselwort gefolgt vom Namespacenamen. Das folgende Beispiel zeigt eine Codedatei, die einen Namespace Widgets mit einem Typ und einem Modul deklariert, das in diesem Namespace enthalten ist.

namespace Widgets

type MyWidget1 =
    member this.WidgetName = "Widget1"

module WidgetsModule =
    let widgetName = "Widget2"

Wenn sich der gesamte Inhalt der Datei in einem Modul befindet, können Sie Namespaces implizit deklarieren, indem Sie das module Schlüsselwort verwenden und den neuen Namespacenamen im vollqualifizierten Modulnamen angeben. Das folgende Beispiel zeigt eine Codedatei, die einen Namespace Widgets und ein Modul WidgetsModuledeklariert, das eine Funktion enthält.

module Widgets.WidgetModule

let widgetFunction x y =
   printfn "%A %A" x y

Der folgende Code entspricht dem vorherigen Code, aber das Modul ist eine lokale Moduldeklaration. In diesem Fall muss der Namespace in einer eigenen Zeile angezeigt werden.

namespace Widgets

module WidgetModule =

    let widgetFunction x y =
        printfn "%A %A" x y

Wenn mehrere Module in derselben Datei in einem oder mehreren Namespaces erforderlich sind, müssen Sie lokale Moduldeklarationen verwenden. Wenn Sie lokale Moduldeklarationen verwenden, können Sie den qualifizierten Namespace nicht in den Moduldeklarationen verwenden. Der folgende Code zeigt eine Datei mit einer Namespacedeklaration und zwei lokalen Moduldeklarationen. In diesem Fall sind die Module direkt im Namespace enthalten; Es gibt kein implizit erstelltes Modul mit demselben Namen wie die Datei. Jeder andere Code in der Datei, z. B. eine do Bindung, befindet sich im Namespace, aber nicht in den inneren Modulen, daher müssen Sie das Modulelement widgetFunction mithilfe des Modulnamens qualifizieren.

namespace Widgets

module WidgetModule1 =
   let widgetFunction x y =
      printfn "Module1 %A %A" x y
module WidgetModule2 =
   let widgetFunction x y =
      printfn "Module2 %A %A" x y

module useWidgets =

  do
     WidgetModule1.widgetFunction 10 20
     WidgetModule2.widgetFunction 5 6

Die Ausgabe dieses Beispiels lautet wie folgt.

Module1 10 20
Module2 5 6

Weitere Informationen finden Sie unter Module.

Geschachtelte Namespaces

Wenn Sie einen geschachtelten Namespace erstellen, müssen Sie ihn vollständig qualifizieren. Andernfalls erstellen Sie einen neuen Namespace auf oberster Ebene. Einzug wird in Namespacedeklarationen ignoriert.

Das folgende Beispiel zeigt, wie sie einen geschachtelten Namespace deklarieren.

namespace Outer

    // Full name: Outer.MyClass
    type MyClass() =
       member this.X(x) = x + 1

// Fully qualify any nested namespaces.
namespace Outer.Inner

    // Full name: Outer.Inner.MyClass
    type MyClass() =
       member this.Prop1 = "X"

Namespaces in Dateien und Assemblys

Namespaces können mehrere Dateien in einem einzelnen Projekt oder einer Kompilierung umfassen. Das Begriffsnamespacefragment beschreibt den Teil eines Namespaces, der in einer Datei enthalten ist. Namespaces können auch mehrere Assemblys umfassen. Beispielsweise enthält der System Namespace das gesamte .NET Framework, das viele Assemblys umfasst und viele geschachtelte Namespaces enthält.

Globaler Namespace

Sie verwenden den vordefinierten Namespace global , um Namen im Namespace der obersten Ebene von .NET einzufügen.

namespace global

type SomeType() =
    member this.SomeMember = 0

Sie können auch global verwenden, um auf den .NET-Namespace der obersten Ebene zu verweisen, z. B. um Namenskonflikte mit anderen Namespaces zu lösen.

global.System.Console.WriteLine("Hello World!")

Rekursive Namespaces

Namespaces können auch als rekursiv deklariert werden, damit alle enthaltenen Code gegenseitig rekursiv sein können. Dies erfolgt über namespace rec. namespace rec Die Verwendung kann einige Schmerzen lindern, die nicht in der Lage sind, sich gegenseitig referenzieller Code zwischen Typen und Modulen zu schreiben. Im Folgenden sehen Sie ein Beispiel dafür:

namespace rec MutualReferences

type Orientation = Up | Down
type PeelState = Peeled | Unpeeled

// This exception depends on the type below.
exception DontSqueezeTheBananaException of Banana

type Banana(orientation: Orientation) =
    member val IsPeeled = false with get, set
    member val Orientation = orientation with get, set
    member val Sides: PeelState list = [Unpeeled; Unpeeled; Unpeeled; Unpeeled] with get, set

    member self.Peel() = BananaHelpers.peel self // Note the dependency on the BananaHelpers module.
    member self.SqueezeJuiceOut() = raise (DontSqueezeTheBananaException self) // This member depends on the exception above.

module BananaHelpers =
    let peel (banana: Banana) =
        let flip (banana: Banana) =
            match banana.Orientation with
            | Up ->
                banana.Orientation <- Down
                banana
            | Down -> banana

        // Update the peel state for all sides of the banana.
        let peelSides (banana: Banana) =
            banana.Sides
            |> List.map (function
                         | Unpeeled -> Peeled
                         | Peeled -> Peeled)

        // Apply the flipping and peeling logic based on the orientation.
        match banana.Orientation with
        | Up ->   banana |> flip |> peelSides
        | Down -> banana |> peelSides

Beachten Sie, dass die Ausnahme DontSqueezeTheBananaException und die Klasse Banana beide miteinander verweisen. Darüber hinaus beziehen sich das Modul BananaHelpers und die Klasse Banana auch aufeinander. Dies wäre nicht möglich, in F# auszudrücken, wenn Sie das rec Schlüsselwort aus dem MutualReferences Namespace entfernt haben.

Dieses Feature ist auch für Module der obersten Ebene verfügbar.

Siehe auch