Different ways to return data in C#
Published: 2021-06-28 04:03:06

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jgzkem14xuaxitikgzog.PNG)

When we write a function with complex logic or when the function calls for a third party resource - aside from the result, we need to be able to receive an indication of whether the function succeeded or failed.
<br/>

###1️⃣ Try/Catch
A common way is the _try/catch_ approach. The critical logic is written in a try block, and if something is wrong you send the appropriate _Exception_ (it is recommended to create your own custom Exception for specific scenarios) and it is handled in the catch block:
```cs
[HttpPost]
[Route("customers"​ )]
public IHttpActionResult CreateCustomer([FromBody] CreateUserRequest request)
{
    try
    {
        var newCustomer = Customer.From(request);
        var result = _customerService.CreateCustomer(newCustomer);
        return Ok(newCustomer);
    }
    catch (CustomerExistsException)
    {
        return BadRequest(Errors.IllegalEmail);
    }
    catch (IllegalEmailException)
    {
        return BadRequest(Errors.CustomerExists);
    }
    catch (Exception e)
    {
        return InternalServerError(e);
    }
}
```

I don’t like this approach for several reasons:

1. _Exception_ are meant to handle... _Exceptions_ and not business logic and error handling.
2. Using Exceptions for business logic is, in fact, _[goto](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/goto)_ pattern, which is a big no-no pattern ❌
3. _Exception_ impact performance 😕
<br/>
<br/>

###2️⃣ TryParse
_TryParse_ is a _.Net_ implementation for type conversion.

Basically, the function returns a _boolean_ indication if the conversion has succeeded, and gets an out parameter to be converted if it succeeds.

You can implement your own _TryParse_ (or other operations that your function needs to do: _TryExecute_, _TryUpdate_ etc…):
```cs
[HttpPost]
[Route("customers"​ )]
public IHttpActionResult CreateCustomer([FromBody] CreateUserRequest request)
{
    var newCustomer = Customer.From(request);
    var succeed = _customerService.TryCreateCustomer(newCustomer, out var customer);
   
    return succeed
        ? Ok(customer)
        : InternalServerError(new Exception(Errors.InternalError));
}
```
This approach is fine, but there are developers that don’t like the idea of sending an out parameter to the function (it contradicts the [functional programming principles](https://docs.microsoft.com/en-us/archive/msdn-magazine/2010/april/fsharp-basics-an-introduction-to-functional-programming-for-net-developers)).  
<br/>

###3️⃣ Tuple
With the _Tuple_ type you can achieve the same idea without sending the out parameter. The only thing you need to do is to return a _Tuple< bool, T>_, where the bool is an indication if the operation has succeeded and the T is the type of the desired value:
```cs
[HttpPost]
[Route("customers"​ )]
public IHttpActionResult CreateCustomer([FromBody] CreateUserRequest request)
{
    var newCustomer = Customer.From(request);
    var (succeed, customer) = _customerService.CreateCustomer(newCustomer);

    return succeed
        ? Ok(customer)
        : InternalServerError(new Exception(Errors.InternalError));
}
```
The problem with the _Tuple_ and the _TryParse_ way, is that while you have a _boolean_ indication if the logic has failed, but you don’t know why.  
<br/>

###4️⃣ Result
Another approach is the _Result_. There are many implementations of this concept such as in the [CSharpFunctionalExtensions nuget](https://www.nuget.org/packages/CSharpFunctionalExtensions/), or in the [LanguageExt nuget](https://www.nuget.org/packages/LanguageExt.Core), and I even wrote a post about this approach a few years ago: [Using Result concept](https://www.linkedin.com/pulse/c-using-result-concept-ziv-ben-or/).

This idea is like the _Tuple_ but in a dedicated _class/struct_ that has a Value parameter for the result, Error parameter – a message text if failed, and _boolean_ parameters that indicates if success or failure:
```cs
public Result< Customer> CreateCustomer(Customer customer)
{
    if (!Common.IsValidEmail(customer))         return Result.Fail(Errors.IllegalEmail);
    if (_users.ContainsKey(customer.IdNumber))  return Result.Fail(Errors.CustomerExists);

    _users.Add(customer.IdNumber, customer);
    return Result.Ok(customer);
}
```
```cs
[HttpPost]
[Route("customers"​ )]
public IHttpActionResult CreateCustomer([FromBody] CreateUserRequest request)
{
    var newCustomer = Customer.From(request);
    var result = _customerService.CreateCustomer(newCustomer);

    return result.IsSuccess
        ? Ok(result.Value)
        : BadRequest(result.Error);
}
```  
<br/>
<br/>
###5️⃣ OneOf
[OneOf](https://github.com/mcintyre321/OneOf/) is a cool 😎 nugget I was introduced to in the past year. [OneOf](https://github.com/mcintyre321/OneOf/) solves the problem of all the other patterns we saw, when it is not enough to know that the function/process failed and you also want to know **why**. For example, in controller in a _Web API_ service you want to know what happened: if it is our failure – to return an _internal server error (500)_, or if it is a data problem to return a _Bad Request (400)_, Also, and also if it is a _Bad Request_, we want more details about what part of the request is bad.

[OneOf](https://github.com/mcintyre321/OneOf/) is a struct that enables you to declare, with generics, how many and what types we expect to get back:
```cs
public OneOf<​Customer, IllegalEmail, CustomerExists> CreateCustomer(Customer customer)
{
   if (!Common.IsValidEmail(customer))        return new IllegalEmail();
   if (_users.ContainsKey(customer.IdNumber)) return new CustomerExists();
 
   _users.Add(customer.IdNumber, customer);

   return customer;
}
```
After you get back the result, you need do _Match/switch-case_ to handle each of the type scenarios that you can get back:
```cs
[HttpPost]
[Route("customers"​)]
public IHttpActionResult CreateCustomer([FromBody] CreateUserRequest request)
{
   var newCustomer = Customer.From(request);
   var result = _customerService.CreateCustomer(newCustomer);
 
   return result.Match<​IHttpActionResult>(
       customer       => Ok(customer),
       illegalEmail   => BadRequest(Errors.IllegalEmail),
       customerExists => BadRequest(Errors.CustomerExists)
   );
}
```
<br/>
<br/>

###6️⃣ Polymorphism
Another way is to use the C# language support of _[Polymorphism](https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/polymorphism)_. We can create an empty _interface_, e.g. IResult, and any type we want to return inherits from this _interface_:
```cs
public interface IResult { }
public struct IllegalEmail: IResult { }
public struct CustomerExists: IResult { }
public struct Customer : IResult { /**...**/ }
```
```cs
public IResult CreateCustomer(Customer customer)
{
   if (!Common.IsValidEmail(customer))        return new IllegalEmail();
   if (_users.ContainsKey(customer.IdNumber)) return new CustomerExists();
 
   _users.Add(customer.IdNumber, customer);
   return customer;
}
```

 Now you can handle any type with _switch statement/expression_: 
```cs
[HttpPost]
[Route("customers"​)]
public IHttpActionResult CreateCustomer([FromBody] CreateUserRequest request)
{
   var newCustomer = Customer.From(request);
   var result = _customerService.CreateCustomer(newCustomer);
   return result switch
   {
       Customer       => Ok(result),
       IllegalEmail   => BadRequest(Errors.IllegalEmail),
       CustomerExists => BadRequest(Errors.CustomerExists)
   };
}
```

For primitive types (_int, bool, float..._) or 3rd-party classes we can use a _struct_ wrapper:
```cs
public struct ResultValue<​T> : IResult
{
   private ResultValue(T value) => Value = value;
   public T Value { get; set; }
   public static ResultValue<​T> From(T value) => new ResultValue<​T>(value);
   public static implicit operator T(ResultValue<​T> result) => result.Value;
}
```
```cs
public IResult UpdateCustomerId(int number)
{
   if (!Common.IsValidIdNumber(number)) return new IllegalIdNumber();
   if (!Common.IsValidIdNumberLength(number)) return new IllegalIdNumberLength();

   Customer.UpdateIdNumber(number);

   return ResultValue<​int>.From(number);

}
```
<br/>

###Summary
In this article we have seen several ways to return data​: _Try/Catch, TryParse, Tuple, Result, OneOf_ and _Polymorphism_. Some solutions are better and some are less good, but there isn’t only one right way. You must not be a fossil - always search for the best solution for your given code 💪
<br/>




Thanks,

Ziv Ben-Or

ZivBenOr@Gmail.com

+972545882011




Check my article in Linkedin: [Different ways to return data in C#](https://www.linkedin.com/pulse/different-ways-return-data-c-ziv-ben-or)