Qu'est-ce qui déclenche le passage des fragments de A à B? C'est là que je mettrais la logique pour effacer cet EditText. Par exemple, si un utilisateur appuie sur un bouton qui déclenche le changement de fragments, effacez le EditText dans la méthode onClick (View view) de View.OnClickListener.

Cependant, je souhaite savoir s'il existe des alternatives à une simple instruction switch:

switch(command.ToLower) {
case "example":
    // do things...
    break;
case "example2":
    // do things...
    break;
}

Je pense qu'il existe une solution plus élégante mais mes compétences ne peuvent y accéder.

MODIFIER: En raison de l'incroyable contribution de @OwlSolo, mon code fonctionne maintenant, j'ai posté ci-dessous ma version modifiée du code soumis qui fonctionne pour moi. Merci @OwlSolo vous êtes une légende en train de taper!

class parseCommand
{
    public static commandBase commandInstance { get; set; }

    public static void parse(string command)
    {
        string[] tokens = command.Split(' '); // tokens[0] is the original command
        object[] parameters = tokens.Skip(1).ToArray();

        List<Type> cmdTypes = System.Reflection.Assembly
            .GetExecutingAssembly()
            .GetTypes()
            .Where(t => typeof(commandBase).IsAssignableFrom(t))
            .ToList();

        foreach(Type derivedType in cmdTypes)
        {
            if (derivedType.Name.ToLower() == tokens[0].ToLower())
            {
                commandInstance = (commandBase)Activator.CreateInstance(derivedType);
                commandInstance.parameters = parameters;
                commandInstance.Execute();
                break;
            }
        }
    }
}
3
AzzaNoodles 23 déc. 2015 à 18:12

4 réponses

Meilleure réponse

L'analyse d'un langage quelconque est fondamentalement une discipline en soi, donc cette question est assez large. Les lexers et les analyseurs de langage créent généralement des arborescences de commandes qui sont séparées en mots-clés et paramètres réservés. Les mots-clés réservés contiennent par exemple des commandes. (comme switch, if, goto, etc. dans les langages de type C) Le fait est que ces commandes sont idéalement choisies de manière à être mutuellement indépendantes. Cela signifie que les mots-clés en eux-mêmes provoquent une manipulation très différente. Le réglage fin se fait via les paramètres.

Si cela s'applique à vos commandes, vous n'avez pas vraiment le choix de fournir des méthodes indépendantes de gestion de chaque commande. Par exemple, JavaCC (JavaCompiler-Compiler) génère une base de code avec des cas de commutation assez volumineux qui génèrent une arborescence d'instructions. Il appartient ensuite à l'utilisateur d'évaluer l'arbre d'instructions fourni, ce qui est généralement fait via des objets individuels qui gèrent les mots-clés - il pourrait donc y avoir une classe IfStatement qui contient un certain nombre d'instructions enfants et gère son exécution.

Tout ce dont vous avez besoin ici spécifiquement, le vrai travail va être, comment vous gérez l'exécution plutôt que comment vous différenciez quelle commande appelle quel comportement.

Une structure que vous pourriez souhaiter pourrait ressembler à ceci:

abstract class BinaryCommand
{
    MyBaseCommand child1;
    MyBaseCommand child2;

    abstract object Execute();
}

class ExampleCommand1 : BinaryCommand
{
    override object Execute()
    {
         //DoStuff1...
    }
}

class ExampleCommand2 : BinaryCommand
{
    override object Execute()
    {
         //Do Somethign else
    }
}

Tenant un {{X0}} à partir duquel vous recherchez le type qui gère une commande. Ainsi par exemple: "Example1 abcde 12345" chercherait "Example1", créerait une instance du type dans le dictionnaire et la classerait avec les paramètres "abcde" et "12345".

  • Une grande instruction de commutation.

  • MODIFIER: avec les informations fournies dans les commentaires, vous pouvez faire quelque chose comme ceci

  • Une manière plutôt audacieuse serait de réfléchir à travers votre code pour une classe capable de gérer la commande.
    Vous auriez une interface comme IBaseCommand dont toutes vos classes de commandes dérivent.

// Get all the types that derive from your base type
List<Type> commandTypes = Assembly
    .GetExecutingAssembly()
    .GetTypes()
    .Where(t => typeof(IBaseCommand).IsAssignableFrom(t));

foreach (Type derivedType in commandTypes)
{
    // Distinguishing by class name is probably not the best solution here, but just to give you the general idea
    if (derivedType.Name == command.ToLower) 
    {
        // Create an instance of the command type
        IBaseCommand myCommandInstance = Activator.CreateInstance(derivedType);
        //Call the execute method, that knows what to do
        myCommandInstance.Execute();
    }
}

Votre objectif est d'avoir le moins de commandes possible et d'en faire autant que vous le pouvez via les paramètres.

Interface ICommandBase
{
    object[] parameters {get; set;}
    void Execute();    
}

abstract class InternalCommand : ICommandBase
{
    //Some methods that are common to all your intzernal commands
}

class SetColorCommand : InternalCommand //Or it might derive from ICommandBase directly if you dont need to categorize it
{
     object[] parameters {get; set;}
     void Execute()
     {
         switch (parameters[0])
         {
              case "background":
                  //Set the background color to parameters[1]
              break;
              case "foreground":
                    //...
              break;
         }
     }
}

class SqlCommand : ICommandBase
// Or it might derive from ICommandBase directly if you don't need to categorize it
{
     object[] parameters {get; set;}
     void Execute()
     { 
          //Parameters[0] would be the sql string...
     } 
}

Ensuite, analysez le tout via:

// Assuming you're getting one command per line and one line is fed to this function
public void ParseCommands(string command)
{
    string[] tokens = command.Split(" ");
    // tokens[0] is the command name
    object[] parameters = (object[])tokens.Skip(1);//Take everything but the first element (you need to include LINQ for this)

    // Get all the types that derive from your base type
    List<Type> commandTypes = Assembly
        .GetExecutingAssembly()
        .GetTypes()
        .Where(t => typeof(IBaseCommand).IsAssignableFrom(t));

    foreach (Type derivedType in commandTypes)
    {
        if (derivedType.Name.ToLower == tokens[0].ToLower) 
        /* Here the class name needs to match the commandname; this yould also be a
           static property "Name" that is extracted via reflection from the classes for 
           instance, or you put all your commands in a Dictionary<String, Type> and lookup 
           tokens[0] in the Dictionary */
        {
            // Create an instance of the command type
            IBaseCommand myCommandInstance = Activator.CreateInstance(derivedType);
            myCommandInstance.parameters = parameters;
            myCommandInstance.Execute(); // Call the execute method, that knows what to do
                 break;
        }
    }   
}

Je suis en train de créer une console de débogage pour mes projets, en prenant les entrées d'un {{X0}}, etc.

3
Yoh Deadfall 23 déc. 2015 à 19:22

Pas vraiment ... la seule chose que je ferais est de diviser les différents types de commandes en différentes méthodes pour les rendre plus rationalisées / élégantes, et d'utiliser des collections génériques pour stocker les commandes qui s'appliquent à chaque type.

Exemple:

List<string> MoveCommands = new List<string>(){"Move", "Copy", "Merge"};
List<string> Actions = new List<string>() {"Add", "Edit", "Delete"};

//.......

if(MoveCommands.contains(inputtext))
    ExecuteMoveCommand();
else if (Actions.contains(inputtext))
    ExecuteActionCommand();

Des trucs comme ça ... la route que vous empruntez ne laisse que l'élégance et la netteté du code ouvertes au jeu.

1
MaxOvrdrv 23 déc. 2015 à 15:20

Vous pouvez faire quelque chose comme:

var lookup = new Dictionary<string, YourParamType> ()  
{
  { "example", a  },
  { "example2", b },
   ....
};

YourParamType paraType;
if (lookup.TryGetValue(command.ToLower(), out para))   // TryGetValue, on popular      request
{       
   //your code
}
0
Vlad Iobagiu 23 déc. 2015 à 15:20

Il y a un an, j'ai résolu le même problème. Je vais donc vous expliquer comment cela fonctionne en utilisant mon code comme exemple, afin que vous sachiez comment concevoir des analyseurs de ligne de commande et comment résoudre votre problème.

La méthode {{X0}} qui accepte les arguments et fait la logique métier.

Dans le cas de Cmd.Net, c'est la classe Command:

public abstract class Command
{
    protected Command(string name);
    public string Name { get; }
    public abstract void Execute(ArgumentEnumerator args);
}

La classe a deux membres:

  1. La propriété Name qui donne un nom à la commande
  2. La méthode Execute qui accepte les arguments et fait la logique métier.

Le ArgumentEnumerator divise le string fourni comme la méthode string.Split mentionnée ci-dessus dans le code d'OwlSolo, mais en d'une manière plus complexe. Il produit des paires clé-valeur du nom de l'argument et de sa valeur.

A titre d'exemple, vous avez une chaîne qui ressemble à ceci:

"/namedArg:value1 value2"

Sera analysé en deux paires. La première paire est un argument nommé avec le nom "namedArg" et la valeur "value1". Le second est un argument sans nom (nom égal à string.Empty) avec la valeur "value2".

La méthode redéfinie {{X0}} prendra le premier argument s'il est sans nom et recherchera la commande en utilisant la méthode {{X1}}. Lorsqu'il trouve la commande, il l'exécute avec tous les arguments sauf le premier. S'il n'y a pas de commande trouvée ou si le premier argument a un nom, alors nous devrions afficher une erreur.

Maintenant, nous voulons avoir une collection de commandes à partir de laquelle vous pouvez prendre plus rapidement l'une d'entre elles par son nom. Et le Dictionary<string, Command> est le meilleur choix, mais voyons plus loin et faisons une commande qui transférera le contrôle à une commande enfant. Nous pourrons donc créer des catégories / hiérarchies de commandes comme dans netsh.

public sealed class CommandContext : Command
{
    public CommandContext(string name);
    public CommandCollection Commands { get; }
    public override void Execute(ArgumentEnumerator args);
}

public sealed class CommandCollection : KeyedCollection<string, Command>
{
    public CommandCollection() 
        : base(StringComparer.OrdinalIgnoreCase) 
    { 
    } 

    protected override string GetKeyForItem(Command item)
    { 
        return item.Name;
    }

    public bool TryGetCommand(string name, out Command command)
    { 
        return Dictionary.TryGetValue(name, out command);
    }
}

La méthode redéfinie Execute prendra le premier argument s'il est sans nom et recherchera la commande en utilisant la méthode TryGetCommand. Lorsqu'il trouve la commande, il l'exécute avec tous les arguments sauf le premier. S'il n'y a pas de commande trouvée ou si le premier argument a un nom, alors nous devrions afficher une erreur.

REMARQUE Puisque nous utilisons StringComparer.OrdinalIgnoreCase, nous ne devons pas nous soucier des casse de caractères dans le name passé.

Il est maintenant temps de penser à l'analyse et à la conversion automatisées des arguments. Pour y parvenir, nous pouvons utiliser la réflexion et les TypeConverter s.

public sealed class DelegateCommand : Command
{
    public DelegateCommand(Delegate method);
    public Delegate Method { get; }
    public override void Execute(ArgumentEnumerator args);
}

Dans le constructeur de DelegateCommand, vous devez rassembler des informations sur les paramètres de method (noms, valeurs par défaut, convertisseurs de type, etc.) et les utiliser plus tard dans la méthode Execute pour convertir et fournir des arguments au method.

J'ai omis les détails de mise en œuvre parce que c'est complexe, mais vous pouvez en savoir plus sur DelegateCommand.cs et dans Argument.cs.

Enfin, vous pourrez exécuter des méthodes sans aucune analyse.

CommandContext root = new CommandContext(
    "root",
    new Command("multiply", new Action<int, int>(Multiplication)),
    new CommandContext(
        "somecontext",
        // ...
        )
    );
ArgumentEnumerator args = new ("add /x:6 /y:7");

root.Execute(args);

public static void Multiplication([Argument("x")] int x, [Argument("y")] int y)
{
    // No parsing, only logic
    int result = x * y;
}
0
Community 23 mai 2017 à 10:27