I was recently talking with a buddy about return values taking only a single meaning. At my previous job, we worked with C++ and had typedef’ed wBOOL so that a 0 was wFALSE, and 1 was wTRUE. The architect said that we can also return 2, 3, 4… for more information, which I think is a horrible idea. If we expect wTRUE = 1 and wFALSE = 0 and wBOOL = {wTRUE, wFALSE}, returning anything else should be avoided… now, on to today’s C#.
I recently reviewed a piece of code where there were a collection of functions that determined if there was an error and returned the string back to the user:
private bool IsTestReady(out string errorMessage)
{
bool isReady = true;
errorMessage = string.Empty;
if(FailureCondition1)
{
isReady = false;
errorMessage = FailureMessage1;
}
else if(FailureCondition2)
{
isReady = false;
errorMessage = FailureMessage2;
}
//... other conditions
return isReady;
}
Then, to use these functions…
private enum Tests
{ TestA, TestB, TestC }
private void UpdateUI()
{
string error = string.Empty;
bool isTestReady;
switch(this.runningTest) // which test are we running (TestA, TestB, or TestC)
{
case Tests.TestA:
isTestReady = IsTestAReady(error);
break;
case Tests.TestB:
isTestReady = IsTestBReady(error);
break;
case Tests.TestC:
isTestReady = IsTestCReady(error);
break;
}
runTestButton.Enabled = isTestReady;
runTestLabel.Text = error;
}
I thought to separate these out into two methods:
private string GetTestAErrorMessage()
{
//same as IsTestReady, but only returns the error string, no boolean stuffs
}
private bool IsTestAReady
{
get{ return string.IsNullOrEmpty(GetTestAErrorMessage()); }
}
Does this violate the principal of not having a return value mean more than one thing? For instance, in this case, if there error message IsNullOrEmpty, then there is no error. I think that this does not violate that principal; my co-worked does. To me, it’s no different than this:
class Person
{
public int Height {get;}
public bool IsTall() { return Height > 10; }
}
Any thoughts or suggestions on a different approach to this issue? I think the out parameter is the worst of the solutions.
I’m not a big fan of having the null or empty return value indicate that nothing is wrong. A better comparison than the one you gave is:
In .NET, it is common practice to use the “bool return with out parameter” pattern you see in your original method (see the various
TryParsemethods, for example). However, if you prefer, another solution would be to create aTestReadyCheckclass with both the boolean and the string as properties. I’ve done something similar with the following class, and been quite happy with it.This allows for the following usage:
It’s concise, while enforcing that failure results provide a failure message, and success results don’t.
On a side note, the structure of your
switchstatement feels like a code smell to me. You may want to consider ways to leverage polymorphism. Maybe make each test have its own class, with anIsTestReadymethod on it?