Die Behandlung und Verarbeitung von Argumenten


Sobald Deine Skripte etwas komplexer werden, wirst du anfangen Argument verwenden zu wollen, um Dein Skript verschiedene Operationen ausführen zu lassen. Wenn Du beispielsweise ein Luftschleusen-Skript schreibst, wirst Du dem Skript sagen wollen, dass es eine Luftschleuse ein- oder ausschalten soll und sogar welche Luftschleuse bedient werden soll. Ich werde euch an dieser Stelle nicht zeigen, wie man ein komplettes Luftschleußen-Skript schreibt, aber ich werde das als Beispiel verwenden, um zu zeigen, wie man die Argumente benutzt und verarbeitet. Die programmierbare Block-API verfügt über einen integrierten Befehlszeilen-Parser, der so konzipiert ist, dass er schnell und einfach zu benutzen ist.

Dieser Parser wird MyCommandLine genannt. Das folgende ist ein grundlegendes Skript, ohne tatsächlich irgendwelche Argumente zu überprüfen.

MyCommandLine _commandLine = new MyCommandLine();

public void Main(string argument)
{
    if (_commandLine.TryParse(argument)) {
        // Der command line parser hat Argumente im String gefunden.
    }
}

Dieser Code initialisiert den Befehlszeilenparser und versucht, das eingehende Argument zu analysieren. Wenn es Argumente findet, gibt die TryParse-Methode true zurück.


Die Argumentformate

Die traditionellen Befehlszeilenformate bestehen aus Argumenten und Schaltern.

Ein Argument ist entweder ein einzelnes Wort oder ein sog. "Quoted String", wenn Du Leerzeichen benötigen. Auf die Argumente wird über ihre relative Position in der Zeichenkette zugegriffen, genau wie auf ein Array - das erste Argument ist Argument 0, das zweite 1 und so weiter.

Ein Schalter ist ein wenig anders. In MyCommandLine wird ein Schalter dadurch gekennzeichnet, dass einem Wort ein Bindestrich vorangestellt wird. Ein Schalter kann nur aus Wörtern bestehen (kein Leerzeichen), aber er kann überall in der Befehlszeile platziert werden. Sie haben keinen Einfluss auf die Indexierung der Argumente.

Lass uns das an einigen Beispielen verdeutlichen. Nimm folgende Befehlszeilen:

open "Luftschleuse 1" in -active

oder

-active open "Luftschleuse 1" in

Diese beiden Befehlszeilen bestehen jeweils aus drei Argumenten, MyCommandLine wird sie entsprechend erkennen:

    open
    Luftschleuse 1
    in

und es hat einen einzigen Schalter:

    -active

Beachte, dass es egal ist, wo sich der active-Schalter befindet, er hat keinen Einfluss auf die Indizies der restlichen Argumente.


Zugriff auf die Argumente und Schalter

Du kannst über die Switch-Methode überprüfen, ob ein bestimmter Schalter angegeben wurde. Füge bei der Prüfung auf Schalter nicht den Bindestrich ein.

// überprüfe, ob der "-meinSchalter"-Schalter gesetzt ist
bool schalterIstGesetzt = _commandLine.Switch("meinSchalter");

Sie erhalten Argumente nach ihrem Ordnungszahl beginnend bei 0, ohne die Schalter mit zu zählen.

// erhalte das erste Argument des string (entweder ein Wort oder ein "Quoted String").
string arg = _commandLine.Argument(0);

Nehmen wir noch einmal das erste Beispiel für die Befehlszeile:

open "Luftschleuse 1" in -active

Dann werden wir das allererste Beispiel etwas anpassen,  um das ganze etwas performanter zu behandeln.

Zuerst benötigen wir eine Möglichkeit, zwischen den Befehlen zu unterscheiden. Das erste Argument wird natürlich die Befehlsanzeige sein. Wir werden ein dictionary erstellen, um diese Befehle zu speichern:

Dictionary<string, Action> _commands = new Dictionary<string, Action>(StringComparer.OrdinalIgnoreCase);

Beachte, dass wir einen case-insensitiven Zeichenkettenvergleicher übergeben, so dass wir sowohl OPEN als auch open akzeptieren.
Als nächstes müssen wir die Befehle initialisieren. Das tun wir im Konstruktor.:

public Program() 
{
    // Verbinde die Open-Methode mit dem open-Kommando
    _commands["open"] = Open
}

public void Open()
{
  // Diese Methode wird den Code beinhalten um die gwünschte Aktion auszuführen
}

Schließlich bearbeiten wir die Main-Methode, um das Dictionary zum Auswählen und Ausführen von Befehlen zu verwenden.

public Program() 
{
    // Verbinde die Open-Methode mit dem open-Kommando
    _commands["open"] = Open
}

public void Open()
{
  // Diese Methode wird den Code beinhalten um die gwünschte Aktion auszuführen
}

Schließlich müssen wir die Behandlung der befehlsspezifischen Argumente in der Open-Methode, die dem open-Befehl zugeordnet ist, finalisieren.

public void Open()
{
    // Überpürfe ob der "acitve" Schalter gesetzt ist
    bool activeCycle = _commandLine.Switch("active");

    // Argument Nr 1 ist der Name der Luftschleuße
    string airlockName = _commandLine.Argument(1);
    if (airlockName == null)
    {
        Echo("Öffne nicht möglich, keine Schleuße angegeben");
        return;
    }

    // Argument Nr 2 sollte entweder "in" or "out", je nachdem ob die inner oder äußere Tür geöffnet werden soll
    string direction = _commandLine.Argument(2);
    if (direction == null)
    {
        Echo($"Öffnen von {airlockName} noch möglich, keine Richtung angegeben");
        return;
    }
    if (string.Equals(direction, "in", StringComparison.OrdinalIgnoreCase))
    {
        Echo($"Öffne Luftschleuße {airlockName} innen...");
        // ... weiterer Code 
    }
    else if (string.Equals(direction, "out", StringComparison.OrdinalIgnoreCase))
    {
        Echo($"Öffne Luftschleuße {airlockName} außen...");
        // ... weiterer Code 
    }
    else
    {
        // Das Argument war keines der erwarteten
        Echo($"Kann Luftschleuße {airlockName} nicht öffnen, da Richtung {direction} nicht definiert ist");
    }
}