How To Apply Functional Programming In C#
Tags: csharp, dotnet, functional, programming
Published: 2023-09-17 10:55:47

---
title: How To Apply Functional Programming In C#
published: true
date: 2023-03-04 00:00:00 UTC
tags: csharp,dotnet,functionalprogramming,programming
canonical_url: https://www.milanjovanovic.tech/blog/how-to-apply-functional-programming-in-csharp
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3ag1wx3dgm41rd0piq0e.png
---
Although **C#** is an **object-oriented programming** language, it received many new functional features in recent versions.

To mention just a few of these features:

- Pattern matching
- Switch expressions
- Records

You're probably already doing **functional programming** without even knowing it.

Do you use LINQ? If you do, then you're doing functional programming. Because LINQ is a functional .NET library.

In today's issue, I will show you how to **refactor** some **imperative code** with **functional programming**.

## Benefits Of Functional Programming

Before we take a look at some code, let's see what are the **benefits** of using **functional programming** :

- Emphasis on immutability
- Emphasis on function purity
- Code is easier to reason about
- Less prone to bugs and errors
- Ability to compose functions and create higher-order functions
- Easier to test and debug

From my experience, I think functional programming is more enjoyable once you get used to it. Starting out, it feels strange because your old object-oriented programming habits will kick in. But after a while, **functional programming** feels easier to work with than imperative code.

## Starting With Imperative Code

**Imperative programming** is the most basic programming approach. We describe a step-by-step process to execute a program. It's easier for beginners to reason with imperative code by following along with the steps in the process.

Here's an example of an `EmailValidator` class written with imperative code:

```csharp
public class EmailValidator
{
    private const int MaxLength = 255;

    public (bool IsValid, string? Error) Validate(string email)
    {
        if (string.IsNullOrEmpty(email))
        {
            return (false, "Email is empty");
        }

        if (email.Length > MaxLength)
        {
            return (false, "Email is too long");
        }

        if (email.Split('@').Length != 2)
        {
            return (false, "Email format is invalid");
        }

        if (Uri.CheckHostName(email.Split('@')[1]) == UriHostNameType.Unknown)
        {
            return (false, "Email domain is invalid");
        }

        return (true, null);
    }
}
```

You can clearly see the distinct steps:

- Check if email is null or empty
- Check if email is not too long
- Check if email format is valid
- Check if email domain is valid

Let's see how we can refactor this using **functional programming**.

## Applying Functional Programming

The basic building block in **functional programming** is - **a function**. And programs are written by composing function calls. There are a few other things you need to keep in mind, like keeping your functions pure. A function is pure if it always returns the same output for the same input.

We can capture each step from the imperative version of `EmailValidator` with a `Func` delegate. To also capture the respective error message together with the validation check, we can use a tuple. And since we know all of our validation steps, we can create an array of `Func` delegates to store all of the individual **functions**.

```csharp
public class EmailValidator
{
    const int MaxLength = 255;

    static readonly Func<string, (bool IsValid, string? Error)>[] _validations =
    {
        email => (!string.IsNullOrEmpty(email), "Email is empty"),
        email => (email.Length <= MaxLength, "Email is too long"),
        email => (email.Split('@').Length == 2, "Email format is invalid"),
        email => (
            Uri.CheckHostName(email.Split('@')[1]) != UriHostNameType.Unknown,
            "Email domain is invalid")
    };

    static readonly (bool IsValid, string? Error) _successResult = (true, null);

    public (bool IsValid, string? Error) Validate(string email)
    {
        var validationResult = _validations
            .Select(func => func(email))
            .FirstOrDefault(func => !func.IsValid);

        return validationResult is { IsValid: false, Error: { Length: >0 } } ?
            validationResult : _successResult;
    }
}
```

Notice that this allows us to do all sorts of interesting things with the `_validations` array. How hard would it be to modify this function to return _all of the errors_ instead of just the first one?

If you're thinking we can use LINQ's `Select` method somehow, you're thinking in the right direction.

## Further Reading

We only scratched the surface of what functional programming is, and what you can do with it. If you want to learn more, here are some learning materials:

- [Functional Programming in C#, by Enrico Buonanno](https://www.manning.com/books/functional-programming-in-c-sharp)
- [Functional Programming With C# Using Railway-Oriented Programming](https://youtu.be/dDasAmowFts)
- [How Function Composition Can Make Your Code Better](https://youtu.be/zuy2j8vxgYc)
- [Make Your ASP.NET Core API Controllers Incredibly Simple With Functional Programming](https://youtu.be/AVA2mKG4WOc)

Thank you for reading, and have a wonderful Saturday.

* * *

**P.S. Whenever you're ready, there are 2 ways I can help you:**

1. [**Pragmatic Clean Architecture:**](https://www.milanjovanovic.tech/pragmatic-clean-architecture?utm_source=dev.to&utm_medium=website&utm_campaign=cross-posting) This comprehensive course will teach you the system I use to ship production-ready applications using Clean Architecture. Learn how to apply the best practices of modern software architecture. [**Join 950+ students here.**](https://www.milanjovanovic.tech/pragmatic-clean-architecture?utm_source=dev.to&utm_medium=website&utm_campaign=cross-posting)

2. [**Patreon Community:**](https://www.patreon.com/milanjovanovic) Think like a senior software engineer with **access to the source code** I use in my YouTube videos and **exclusive discounts** for my courses. [**Join 820+ engineers here.**](https://www.patreon.com/milanjovanovic)