Click here to Skip to main content
15,867,985 members
Articles / Programming Languages / C#

Alternative to the C# out keyword using Generics, Anonymous methods and Type converters

Rate me:
Please Sign up or sign in to vote.
2.88/5 (10 votes)
12 Jul 20066 min read 55.5K   124   12   15
This article will demonstrate an alternative to the C# out parameter for those times when you need to get a value back from a method plus some additional information. I'll show you how generics and anonymous methods can be used together to help you write cleaner resuable code.

Contents

Introduction

I really don't like the C# out keyword. I don't like its syntax and the fact that it makes method signatures look so weird. Worse than that though is the way it forces consumers of your code to also write the directive and code 'around it'. I can fully appreciate its purpose and why the designers put it into the C# language spec, but I can't help feeling it could have been done in a cleaner / better way. This article will show you how you can do without the out keyword for certain types of methods by using generics, anonymous methods and implicit / explicit type converters.

What Problem Am I Trying to Solve?

It's probably best to show an example of where the out keyword is used.

Microsoft has used the keyword in the framework. One example is in the Int32.TryParse() method. In order to return a value and a bool back to the caller, they resorted to doing this:

C#
int value;
if (Int32.TryParse("123", out value)) {
   //  we have a real integer
}

// or the more natural (but exception prone) way
value = Int32.Parse("123");

Personally, I feel that the last line looks much cleaner, neater, easier to read and more to the point. You are calling a method that returns a value (just like 90% of the .NET Framework methods do) and your variable will be set or an exception is thrown.

If you have a method that should return a bool and a value, then you're stuck with this pattern (and the dreaded out keyword) unless you decide to return a bespoke object from the method which contains both the value and the return result. Writing another class to get around the out keyword isn't ideal. It introduces a class that exists for perhaps a single method and leaves you with the decision of where to put the class. If the out keyword was bad, this is downright awful.

The out keyword lets us return other values to the caller but it doesn't really help them. Let's say that you called the first method which returned a bool value of false. What does this mean? Of course, at a high level it means that the string passed to the method did not parse into an integer - but why exactly did it fail? All we know is that the string isn't valid for some reason.

C#
int value;
if (!Int32.TryParse(txtAge.Value, out value)) {
   //  ok, we failed to parse the input but why????
}

Wouldn't it be nice if you could pass a message back like "the value you supplied was too big" or "the value contained letters" instead of giving the user a catch all message like "sorry that does not compute". Of course, we can do this by throwing an exception, but it's a performance bottleneck and it forces the consumer of your method to write exception handlers (which I suspect is why Microsoft created the TryParse() method instead).

So, we can sum up the problem by specifying what goals our solution should have. It should:

  1. pass back a value to the caller
  2. pass back a bool indicating if the method succeeded or not
  3. if it failed, then it should give a reason why
  4. if it is warranted, then an exception object should be made available to the caller for them to throw if really necessary
  5. finally, the solution should be unobtrusive and shouldn't change the pattern of function calling like the out keyword has

Solution

We can provide a reusable generic solution to this problem by making use of generics, type converters and anonymous methods. If we can return a reusable rich object which allows the consumer to get the value, message or exception and still write code that looks natural, then I think we're on to a winner.

My Result<T> class provides a solution to all of those requirements and is small enough to not cause any memory or performance issues due to the use of generics. Let's take a look at the Result<T> class below:

C#
/// <summary>
/// Reusable generic result class which allows a value, exception
/// or message information to be passed back to a
/// calling method in one go.
/// </summary>
/// <typeparam name="T">The expected return type</typeparam>
public class Result<T> {

  protected T result = default(T);
  protected string message = string.Empty;
  protected Exception exception = null;
  protected Predicate<T> boolConverter = delegate { return true; };

  public Result(T result) : this(result, string.Empty, null, null) {}
  public Result(T result, Predicate<T> boolConverter) :
          this(result, string.Empty, null, boolConverter) { }
  public Result(T result, string message) : this(result, message, null, null) { }
  public Result(Exception exception) : this(default(T),
              string.Empty, exception, null) { }
  public Result(T result, string message,
          Exception exception, Predicate<T> boolConverter) {
    this.result = result;
    this.exception = exception;
    if (exception != null && message == string.Empty)
      this.message = exception.Message;
    else
      this.message = message;
    if(boolConverter!= null)
      this.boolConverter= boolConverter;
  }

  public T ActualResult {
    get { return this.result; }
  }

  public string Message {
    get { return this.message; }
  }

  public Exception Exception {
    get { return this.exception; }
  }

  public bool Success {
    get { return CheckForSuccess(this); }
  }

  public static explicit operator bool(Result<T> result) {
    return CheckForSuccess(result);
  }

  static bool CheckForSuccess(Result<T> result) {
    return result.Exception == null &&
            string.IsNullOrEmpty(result.message) &&
            result.boolConverter(result.ActualResult);
  }

  public static implicit operator T(Result<T> result) {
    if (result.Exception != null)
      throw result.Exception;
    if(!result.boolConverter(result.ActualResult))
      throw new Exception("Result failed the boolConverter test
              and is not guaranteed to be valid");
    return result.ActualResult;
  }
}

How To Use It

The first thing to notice is that the class takes a generic parameter when you define an instance of it. If we were to write a wrapper around the Int32.TryParse() method, then it would look something like this:

C#
public Result<int>ParseInt(string sValue) {
  int value;
  if (!Int32.TryParse(sValue, out value)) {
    // more investigation required into why it failed here
    return new Result<int>(new Exception
    ("String couldn't be converted to an integer"));
  }
  return new Result<int>(value);
}

How Does this Work from the Calling Method's Side?

This is where the pattern really kicks in. The consumer can now decide how they want to use your method. There are no less than two ways to call the ParseInt() method.

Method 1 (the 'confident' method): Treat the return result as a normal value:

C#
public void DoSomething(string sValue) {
   // the ParseInt method will throw an exception if the string 
   // wasn't successfully parsed
   int value = ParseInt(sValue);
}

Method 2 (the 'defensive' method): Treat the return result as a result object

C#
public void DoSomething(string sValue) {
  // the ParseInt method will throw an exception 
  // if the string wasn't successfully parsed
  Result<int> value = ParseInt(sValue);
  if((bool)value) {
    // get the int out of the result
    int intValue = value.ActualValue;
  } else {
    // tell everybody why it failed
    MessageBox.Show(value.Message);

    // or you could do this
    // throw value.Exception;
  }
}

Anonymous Methods

Say we wanted to extend the ParseInt() method so that it only returned true for integers that were:

  1. successfully parsed and 
  2. greater than zero?

That's where the anonymous methods kick in. The Result<T> class provides an alternative constructor which allows a delegate to be passed to it. The delegate is then inspected when the type converters are called or when the Success property is inspected.

C#
public Result<int>ParseInt(string sValue) {
  int value;
  if (Int32.TryParse(sValue, out value)) {
    // more investigation required into why it failed here
    return new Result<int>(new Exception("String couldn't be converted to an integer"));
  }
  return new Result<int>(value, 
    delegate(T obj) {
      if (Convert.ToInt32(obj) > 0)
        return true;
      return false;
    };
  );
}

The result is now only valid when the value is greater than zero.

Type Converters

Explicit

The Result<t> class makes use of both implicit and explicit type converters. The class will always explicitly convert to a bool which indicates whether the method succeeded or not. The value returned can be checked by querying the Success property as well as using the explicit conversion.

C#
Result<int> value = ParseInt(sValue);
if((bool)value) { // this invokes the explicit type converter
}

Implicit

Generally speaking, implicit type conversions can be quite dangerous. One object turning into another type of object without your realising it doesn't exactly set your pulse running, but with the Result<t> class, it is a perfect fit. If you want to treat the Result as the native type, then it will attempt to convert it for you automatically. However, if the method returns a failure result, then an exception is thrown at the point where the conversion takes place. This is to prevent you from using a result which is not valid without you realising it.

C#
Result<int> value = ParseInt(sValue);
if(value > 99) { // this invokes the implicit type converter and may throw an exception
}

Extending the Class

It might be beneficial to extend the Result class for particular datatypes. I know that this goes some way against the whole generics idea but in doing so could allow more specialised results to be put in place. For example, if the result is always numeric, then a sub class could be written that extends Result<t> and adds some standard boolean tests such as:

C#
public static Predicate<T> GreaterThanZero {
  get {
    return delegate(T obj) {
      if (Convert.ToInt32(obj) > 0)
        return true;
      return false;
    };
  }
}

Adding these sort of helper methods nicely encapsulates the logic of the class - yet still allows it to be extended.

Summary

I hope that somebody out there finds this simple class useful. I have used the pattern in a number of large projects and it's been extremely useful to me. I'd love to hear from anybody who uses the class and especially those who extend it.

History

  • 13 July, 2006
    • Fixed code typos, thanks to Murat (muysal81@yahoo.com) for pointing them out
    • Small styling fixes
  • 12 July, 2006
    • Initial article

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United Kingdom United Kingdom
I'm a Technical Architect working for a fairly large retail company in the UK. I've been involved in the software industry for over 12 years now and started out writing compiled BASIC under DOS.

My current weapon of choice is C# and have been using it since late 2000 when it was still in Beta.

The last few years I've moved into a more hands off role but code is where it's at and I like to keep in touch with the latest developments by runing my own open source project and writing articles for CodeProject of course!

Comments and Discussions

 
GeneralRoom for improvement Pin
Alois Kraus12-Jul-06 10:54
Alois Kraus12-Jul-06 10:54 
GeneralRe: Room for improvement Pin
Steve Ward UK12-Jul-06 12:17
Steve Ward UK12-Jul-06 12:17 
GeneralRe: Room for improvement Pin
Alois Kraus12-Jul-06 12:41
Alois Kraus12-Jul-06 12:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.