7

I can think of the following ways to return multiple values from a method (and one which splits into two methods)

private bool IsCarFaulty(Car car, out string fault)
{
  fault = string.Empty;
  return false;
}

private Tuple<bool, string> IsCarFaulty(Car car)
{
  return Tuple.Create(false, string.Empty);
}

private ResultAndMessage IsCarFaulty(Car car)
{
  return new ResultAndMessage(false, string.Empty);
}

private bool IsCarFaulty(Car car)
{
  return false;
}

private string GetCarFault(Car car)
{
  return string.Empty;
}

Basically my question is, are there situations where one is preferable over the other? If I take int.TryParse for an example. It uses an out parameter, but couldn't splitting it into two methods CanParse and Parse work just as well, if not better.

1
  • 3
    CanParse and Parse would parse the integer twice. Commented Aug 17, 2012 at 23:48

6 Answers 6

4

The problem with separate CanParse and Parse methods is that you have to pay the cost of parsing twice - once in CanParse and then again in Parse. This can be especially problematic when the parsing is quite complex and time-consuming (for example for types like DateTime).

Sign up to request clarification or add additional context in comments.

1 Comment

You only answered part of the question ;)
3

Basically my question is, are there situations where one is preferable over the other?

Sure, but I don't think there is a general rule that applies to all cases. Just pick the one you feel more comfortable with on a case by case basis.

I usually avoid using out parameters, because they don't play well with Linq.

If I take int.TryParse for an example. It uses an out parameter, but couldn't splitting it into two methods CanParse and Parse work just as well, if not better.

Sure, it could work, but that means the string would be parsed twice, which is suboptimal.

When int.TryParse was introduced, C# didn't have nullable types (EDIT: actually it did); now you could write a method like that:

public static int? TryParseInt32(string s)
{
    int i;
    if (int.TryParse(s, out i))
        return i;
    return null;
}

4 Comments

Nullable types and int.TryParse where both introduced with .NET2.0.
@JonHanna, thanks for pointing this out, I thought TryParse was there from the start... In this case it seems pretty dumb they didn't provide a TryParse overload that takes a string and returns a Nullable<T> ;)
Yeah, it does seem natural. It may have been in the beta earlier, done by a different team, made to match some other library somewhere (consider how the Windows API has hundreds of cases where return indicates success and the value wanted is written through a pointer - this is the closest .NET form), decided upon when they weren't sure nullable wouldn't be dropped, or another internal reason that makes it perfectly sensible. Or they could have liked the separation of the success indicator from the value.
Or they may have wanted the pattern to match cases where it might be used with nullable types for the value, in which case you can't use it since there'd be no way to distinguish failure from successfully getting a null.
3

I prefer creating a strongly-typed "Result" object to encapsulate the return values from methods, when more than one value is being returned. However, it's also possible that needing to return multiple values is a sign that your method is doing too much and could be refactored .

For example, your method is returning a bool for whether the car is faulty, and a message. Why not have the method return an enum value for the type of failure, and then have a method responsible for translating that value into an error message?

Comments

2

Options:

  1. out
    • fast, that's why it is used in framework libraries, you can't trade speed for anything else in those
    • bad design, doesn't go well with LINQ and any chained code really
    • easy to code
  2. Tuple<>
    • slow, creates small objects, should rarely be very costly in practise though, because it's said to be very well optimized in .NET. I did find that to be an issue on several occasions though.
    • bad maintainability, no names for fields, code is not self-documented
    • easy to code
  3. Result
    • slow
    • good maintainability
    • more code

Obviously nobody can say what's better for your particular case, so choose yourself.

Comments

1

the best way to return multiple value is to return an object ( a class that wrapp all you value in properties) that is

private ResultAndMessage IsCarFaulty(Car car)
{
  return new ResultAndMessage(false, string.Empty);
}

with class ResultAndMessage having two properties (bool and string)

Comments

0

I prefer bool return with an out for TryXXX methods like TryParse, TryDeque etc. for a few reasons.

  1. The "parts" of the result are very separate things, and I like that they're kept separate.
  2. The return type is the same over all the variants of this. So that's consistent.
  3. The out type is always one closely connected to the type or object called on, either by being the type itself (as in int.TryParse) or a type-parameter to the type (as in Dictionary<TKey, TValue>.TryGet and ConcurrentQueue<T>.TryDequeue). So that's consistent.
  4. It's become an easily recognisable pattern within .NET. So that's consistent.

The last point has a down-side in that people may turn to it when something else is more appropriate (assuming valid input and successful operation and throwing an exception if that in't the case, is often better).

I avoid out in other cases, it doesn't chain well, which in turn means it's not very handy in lambda expressions either.

I prefer an object that encapsulates the different values when it's likely to be of further use in itself. Otherwise it's just another class to learn about.

I prefer tuples when the there's a nice clear reason why something is returning two different values at the same time, but it doesn't fit with the above about a new object of use in itself.

I prefer only returning a single result in the first place, most of all.

With the car-fault example, I'd either return a single object that represented the fault that could be null if it wasn't faulty, a single object that represented the car's state of which "no faults found" could be a possible value, or best of all since cars can have more than one fault (and indeed seem to develop several expensive ones just before an NCT/MOT/your-country's-equivalent) an enumerable or queryable object that would let me iterate or query to find all the faults, which would be empty (as in Count == 0) if there were no faults.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.