When should the `out` parameter be used instead of returning a complex type?

When should we use the out parameter in C #?

for example

 bool TryGetValue(out object value); 

against.

 class ReturnType { public bool Found {get;set;} public object Value {get;set;} } ReturnType TryGetValue(); 

Besides reducing the number of lines of code, when should the out parameter be used and when should it be returned as a return type?

+6
c #
source share
12 answers

The output can also be used for operations that may fail (usually in methods starting with Try *).

eg. TryParse will return a bool indicating success / failure, using out as the result. This avoids exceptions.

+4
source share

You have nailed exactly why it should be used. To reduce code complexity.

 if (TryGetValue(myObj)) { [...] } 

more accurate than

 Result tryGetValueResult = TryGetValue(); if (tryGetValueResult.Found) { [...] } 

It can also store on garbage when the result should be a reference type.

+3
source share

If there is no common reason for encapsulating multiple values ​​together, except for this call, then creating a separate type probably happens from above.

On the other hand, if you have several output parameters and a return value that all logically belong to each other (for example, first name, last name, phone number), then it probably makes sense to create an appropriate type (for example, “Contact”)) and return it.

One alternative for the TryGetValue option is to use value types with a null value if the value in question is a value type. For example, int.TryParse could have a signature:

 int? TryParse(string text) 

(with overload, of course, with IFormatProvider ).

+3
source share

They are useful in a (rare) situation in which you need to return a value from the constructor. For example, the Mutex constructor has a boolean out parameter that is set to indicate whether a new Mutex was created or if an existing mutex with the name exists.

+3
source share

The out keyword provides several actions using the compiler.
The caller must not initialize the parameter. The call cannot read from the parameter, but must write to it before exiting the method.

more importantly makes visibility visible , as the caller must specify the out keyword when calling the method

You can use it when you need to return several values ​​from a method (without superimposing and destroying them from the [] object). (A section that likes to return bSuccess from each function will love the out keyword.)
In the above example. The first TryParse return value is the success of the parsing operation. Thus, this is a return value, but the most likely subsequent necessity would be to get the analyzed object if it succeeded. So instead of getting all the callers to take this step, TryParse saves you the trouble of providing it as an out parameter ... because it already did this as part of the CanParse check.

+2
source share

The output options are usually on the fragile side. Moving beyond the scope of the example and considering the problem as a whole: Bill Wagner's book, More Effective C #, describes a fairly thought-out approach to this, it is also described in detail.

In this case, the following code will work.

 public class Tuple<T1,T2> { public T1 First {get;private set;} public T2 Second {get; private set;} Tuple(T1 first, T2 second) { First = first; Second = second; } } using ComplexPair = Tuple<bool,object>; public class SomeOtherClass { public ComplexPair GetComplexType () { ... return new ComplexPair(true, new object); } } 
+1
source share

It would be better to use something like the Option type as a container for return types that might be missing. They are common in most functional languages ​​such as Scala. Useful for the case when you care about something succeeding or failing, and you don't care why. e.g. Parsing integers.

 int num; // mutable = bugprone if (!int.TryParse(str, out num)) // branching = complexity num = someDefault; 

Using the Option type, you can define an int parser that completes volatile ugliness and returns a clean parameter. it reduces your complexity if it is possible only in ONE PLACE. avoids duplication and mutation.

  public Option<int> IntParse(string str) { int num; // mutable if (!int.TryParse(str, out num)) return Option.None<int>(); else return Option.Some<int>(num); } 

use elsewhere:

 int result = IntParse(someString).GetOrElse(defaultValue); 

As you can see, this leads to a much more complex usage pattern, since the branching was hidden.

Alternatively, if your function should return two things, it is likely that:

  • The function is too complex and needs to be shared (do something well!) Or
  • Return values ​​are closely related and should be related to each other in a new type

Thing to think about!

+1
source share

If the object can be null. Then no need to install.

0
source share

I would vote for using a return type. Despite the fact that C # is not a functional language, I believe that it is good to focus on a functional programming style. Not for academic purity, but for pragmatic advantages, when the behavior of each function is not mysterious, without side effects.

0
source share

If you expect your function to simply return a reference to the outgoing object or create a new object, then only the out parameter should be used.

0
source share

Both are correct in my discovery, however I find returning a complex type more elegant, especially if it's a generic type

 ReturnType<T> 

this gives more information about what to expect, there will be a value, so you do not guess the type of the original Value and do the casting.

0
source share

I like to reserve return values ​​for success metrics. Either just true / false for success, or something more complicated, like 0 for success, and other values ​​indicating what happened.

This means that a programmer can verify success on every function that you write. (of course, not everyone will, but they can)

Then, parameters are required to extract the values ​​from the function.

-3
source share

All Articles