C# Command line interpreter

Pagina: 1
Acties:

Onderwerpen


  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
Voor communicatie tussen computers of computer/arduino maak ik vaak gebruik van een string die verzonden wordt en geïnterpreteerd wordt door de ontvanger. Bijvoorbeeld als tussen computers berichten verstuur dan zal het meestal in de vorm van een string zijn: "mediaplayer start" of "mediaplayer open http://www.domein.nl/liedje.mp3". Tussen computer en arduino gaat het nog via een HTTP request, maar die wordt ook direct naar een string omgezet.

Echter als je meerdere applicaties op een apparaat hebt draaien dan worden mijn programeer resultaten altijd een quick en dirty oplossing, zodat het werkt, maar trots ben ik er niet op.

Ik definieer mijn berichten meestal als volgt: "applicatie actie [extra variabelen, ...]" en kom dan met de volgende oplossing:

code:
1
2
3
4
- pak eerste attribuut en gooi deze in een switch case statement
- als er een switch case is met de applicatie naam interpreteer resteren de variabelen
- pak eerste attribuut en test deze in een switch case state ment
- als er een match is; voer stuk code uit welke specifieke actie uitvoert met de variabelen

Switch case in switch case, met daarin weer allemaal if-statements die acties uitvoeren. Dit kan met meerdere applicaties en acties best uit de hand lopen en onoverzichtelijk worden.

Maar het kan voorkomen dat er meerdere applicaties zijn met aparte variabelen en dan krijg ik het een gevoel wordt van alles keihard programmeren, zonder er netjes structuur in te brengen. Op het internet vond ik het volgende voorbeeld: http://cmdline.codeplex.com/ en dit vind ik een netjes begin alleen zit even met het volgende.

Bij een applicatie mediaplayer die bepaalde acties heeft en één a twee extra variabelen (bestandpad) dan kun je deze heel mooi instellen, maar als je meerdere applicaties hebt die acties moeten uitvoeren dan krijg ram je er allemaal variabelen in waarvan je niet de correcte verplicht kunt maken en dit later nog moet checken.

Dus ik stel het volgende voor: CLI in CLI. De eerste CLI interpreteert eigenlijk alleen de applicatie naam en gooit deze dan verder naar de applicatie CLI die de resterende attributen doorneemt en vanaf hier actie onderneemt.

Nu is mijn vraag alleen even of mijn gedachtegang (naast duidelijk) correct is of dat ik dit mogelijk toch met een enkele CLI kan oplossen.

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 01-07 21:58
Het probleem wat je beschrijft is eigenlijk inherent aan deze aanpak, je kunt het deels oplossen door n.a.v. het eerste argument de hele controle over te geven aan een andere class om alles een beetje gespreid te houden. Maar het klinkt alsof je dit helemaal niet nodig hebt. Waarom stuur je acties niet gewoon als (gesynchroniseerde) objecten door naar de applicaties? Via bijvoorbeeld sockets (toch wel de makkelijkste manier tussen meerdere computers).

Je moet dan natuurlijk wel a.d.h.v. variabelen/objecten dan weten wat de andere gaat doen. Kijk daarvoor eens naar het command pattern en double dispatch. Beide zijn geen instant oplossing voor je probleem maar zetten je misschien wel aan het denken.

Wikipedia: Command pattern
Wikipedia: Double dispatch

Een heeeeel andere aanpak zou zijn het maken van een super simpele parser. In deze vorm:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//class play token
string parse(string message)
{
    if(message.startsWith("play "))
    {
        message = // de string message zonder het eerste stuk "play ";
        
        //Paas verantwoordelijkheid van de informatie voor het play argument
        //door aan de volgende parser, deze eet nog een stuk van de string af
        //en vult info;
        PlayInfo info = new PlayInfo();
        
        //De rest van de string bevat andere commando's
        return playArguments.Parse(message, info);
    }
    else
    {
        return message;
    }
}


In de buitenste lus kun je dan alle mogelijke opties (play, stop, etc..) blijven aanroepen totdat de string leeg is of totdat alle opties afgaan de string niet leger maakt (input error). Dit vergt natuurlijk wel wat werk maar maakt je code super makkelijk uitbreidbaar.

~ Mijn prog blog!


  • Hydra
  • Registratie: September 2000
  • Laatst online: 10-07 13:07
Als je iets in de trant van <applicatie> <commando> <opties> hebt zou ik een structuur maken met 'handlers' die de strings voor 'hun' applicatie afhandelen. Je hebt 1 interface ('ICommandHandler') ofzo met een 'handleCommand(string)' methode die elke handler moet implementeren. Dan maak je per applicatie een aparte handler class.

In een configfile (ofzo) geef je aan dat applicatieX calls afgehandeld worden door "AppXHandler" en dat applicatieY calls afgehandeld worden door AppYHandler. Die kun je via reflection laden. Wat je CLI programma dan alleen maar hoeft te doen is bij een commando als "applictiex start muziek.mp3" de juiste handler op te zoeken en dan die hele string door te zetten naar de bijbehorende handler. Dit heeft als voordeel dat je 'hoofd' CLI geen enkele kennis heeft van de onderliggende handlers behalve welke hij moet laden.

Dit is makkelijk pluggable: je hoeft voor een nieuwe applicatie alleen maar een extra handler te schrijven die "ICommandHandler" implementeert en die in de config op te nemen. Dit is ongeveer hoe applicatieservers omgaan met verschillende protocollen zoals ftp, http en https. Ze weten niet wat het is, ze weten alleen welke protocolhandler ze moeten aanroepen.

Ik hoop dat je het verhaal een beetje volgt ;)

[ Voor 14% gewijzigd door Hydra op 27-09-2012 12:32 ]

https://niels.nu