2

I have a class that follows the Command Pattern. It has 2 methods which are Execute, and CanExecute which checks whether to invoke Execute or not (they derive from ICommand). CanExecute invokes a few methods that check that all required services are running, the version is correct, etc.

After CanExecute is invoked, it may fail and return false and I need to know why. Is it because of a bad version, services, missing file, etc.

What is the best strategy to know what is the problem

One option is whenever a required condition fails I can throw an exception that will describe the error in the message field. However the possibility that it will fail is expected and you shouldn't use exceptions for regular flow of control. So I'm really not sure.

Thank you.

Community
  • 1
  • 1
MasterMastic
  • 19,099
  • 11
  • 59
  • 86
  • Seems like you want a State Machine. – Austin Salonen Feb 06 '13 at 16:42
  • @AustinSalonen I'm looking it up but I'm not really following what you mean, could you elaborate (perhaps in an answer if appropriate)? – MasterMastic Feb 06 '13 at 16:44
  • Ken could you perhaps formulate a better question so that someone can provide an appropriate answer..? – MethodMan Feb 06 '13 at 16:45
  • @DJKRAZE I reformulated, I hope it's okay now. If not, I'm sorry and I'm going to need more information why. Thank you for your concern. – MasterMastic Feb 06 '13 at 17:02
  • Does the UI need to present the reasons CanExecute() returned false to the user? Or, do you as the developer just need the information for development purposes? – John Laffoon Feb 07 '13 at 12:59
  • @JohnLaffoon It's presented to the user, but since it's a library so every application should decide if it wants to handle it itself. See the third comment in Jordao's answer, and I think you'll get the general idea. – MasterMastic Feb 07 '13 at 13:09

3 Answers3

1

UPDATE: Reworked based on feedback.

Since the UI needs the reasons CanExecute() returns false, two things come to mind:

Option 1: Add an enumerable message property to the command interface and populate it as needed during the call to CanExecute(). The UI could then interrogate the property as needed. If you go this route, make sure you clear out the contents of the property each call to CanExecute() so you don't lose track of state.

public interface ICommand
{
    IEnumerable<string> Messages { get; }
    bool CanExecute();
    void Execute();
}

public class SomeCommand : ICommand
{
    public IEnumerable<string> Messages { get; private set; }

    public bool CanExecute()
    {
        var messages = new List<string>();

        var canExecute = true;

        if (SomeCondition)
        {
            canExecute = false;
            messages.Add("Some reason");
        }

        if (AnotherCondition)
        {
            canExecute = false;
            messages.Add("Another reason");
        }

        Messages = messages;

        return canExecute;
    }

    public void Execute() { }
}

Option 2: Have CanExecute() return an object which contains the bool as well as an enumerable messages property. This makes it obvious that the messages only apply to that call of CanExecute(). However, depending on where/how you're implementing (e.g. data binding), this could complicate other scenarios more than you're looking for.

public class CanExecuteResult
{
    public bool CanExecute { get; set; }
    public IEnumerable<string> Messages { get; set; }
}

public interface ICommand
{
    CanExecuteResult CanExecute();
    void Execute();
}

public class SomeCommand : ICommand
{
    public CanExecuteResult CanExecute()
    {
        var result = new CanExecuteResult { CanExecute = true };
        var messages = new List<string>();

        if (SomeCondition)
        {
            result.CanExecute = false;
            messages.Add("Some reason");
        }

        if (AnotherCondition)
        {
            result.CanExecute = false;
            messages.Add("Another reason");
        }

        result.Messages = messages;

        return result;
    }

    public void Execute() { }
}

Obviously, the specifics of how you want to handle the interfaces, enumerable types, etc. is up to you. The code is just a representation of the idea.

John Laffoon
  • 2,795
  • 2
  • 24
  • 38
  • The command is at a library which a UI uses. I can't make the library depend on the UI and I also don't want to hard-code it like you've described. – MasterMastic Feb 06 '13 at 18:10
  • In my example, ConditionA and ConditionB are arbitrary representations of whatever method(s) you're using to determine the return value of CanExecute(). Obviously, you would have to write your own code to determine whether or not the value is true/false in addition to whatever information you need to log/present. – John Laffoon Feb 06 '13 at 20:05
  • I'm not sure you really understand, which is probably my fault, so let me try again. The command class, which is also the one that checks everything, is in one library assembly. The GUI is in another assembly. Now for example if `CanExecute` returned false because of a paused driver, I want to tell the user that, and ask him if he wants the application to start it automatically. (And because it's in a library, another GUI assembly could require a different action, so I can't hard-code anything in the library, which is my dilemma). – MasterMastic Feb 06 '13 at 21:36
1

You can use a collection of "reasons" that will tell the users of the class why CanExecute returned false. The reasons can be a simple IEnumerable<string>.

public bool CanExecute() {
  var messages = new List<string>();

  if (!Condition1) {
    messages.Add("Missing Condition1");
  }

  ...

  Messages = messages;
  return messages.Count == 0;
}

public IEnumerable<string> Messages { get; private set; }

Then, client code can show the collection of messages to end-users.

UPDATE:

You can also associate new commands with the messages to give the users ways to fix the problems found. In this case, instead of an IEnumerable<string>, you can create your own class that encapsulates that information:

public class Message {
  public string Text { get; set; }
  public ICommand Command { get; set; }
}

...

public bool CanExecute() {
  var messages = new List<Message>();

  if (!Condition1) {
    messages.Add(
      new Message { 
        Text = "Missing Condition1", 
        Command = new FixCondition1Command() 
      }
    );
  }

  ...

  Messages = messages;
  return messages.Count == 0;
}

public IEnumerable<Message> Messages { get; private set; }
Jordão
  • 51,321
  • 12
  • 105
  • 132
  • I thought about it, but I want to have a chance to recover from the error, and if I'd use your method I would have to do it by comparing strings which probably isn't a best practice. – MasterMastic Feb 06 '13 at 18:15
  • @Ken: I see what you mean. I've added an idea for that. – Jordão Feb 07 '13 at 06:57
  • Ah, I thought of something similar. I thought of raising events and have in the `EventArgs` an id object so the program would recognize the problem and a message string (for the user) which is pretty similar to your idea, but I thought it was a bad idea because events aren't designed for those kind of stuff. Do you mind sharing your opinion? I really appreciate your efforts (you have no idea), thank you! – MasterMastic Feb 07 '13 at 12:47
  • @Ken: I'd prefer not to use events because semantically these condition violations are not "events", they're just "return values" from the `CanExecute` call. – Jordão Feb 07 '13 at 13:57
  • Oh, I see what you mean. Well I guess I could use a tuple. Thank you very much! – MasterMastic Feb 07 '13 at 16:59
0
    Bool CanExecute()
    {
     if(!CheckXXX)
      throw new Exception("CheckXXX function throws an exception")

     if(!CheckYYY)
      throw new Exception("CheckYYY function throws an exception")

    if(!CheckZZZ)
     throw new Exception("CheckZZZ function throws an exception")

    return true; //everything is working fine    
}
Som Poddar
  • 1,348
  • 14
  • 22