Functional Programming in C#: A Practical Guide

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Functional Programming in C#: A Modern Approach to Development



Functional Programming (FP) is a paradigm in which computation is treated as the evaluation of mathematical functions and avoids changing state and mutable data. Although C# was originally created as an object-oriented language, starting with version 3.0 it has been actively incorporating elements of the functional approach. Today, functional programming in C# is not just a trendy fad, but a powerful tool for writing more predictable, testable, and concurrency-safe code.



In this article, we will break down the key concepts of FP as applied to C#: pure functions, data immutability, LINQ, closures, and lambda expressions. You will see how these techniques help write concise and reliable code in the .NET ecosystem.



1. Pure Functions and the Absence of Side Effects



A pure function is a function that:

  • Always returns the same result for the same arguments (referential transparency).
  • Has no side effects (does not modify global variables, does not perform input/output, does not change passed arguments).


In C#, a pure function might look like this:



// Pure functionpublic int AddPure(int a, int b){    return a + b;}

// NOT a pure function (side effect — console output and modification of a global variable)private int _state = 0;public int AddImpure(int a, int b){ _state++; Console.WriteLine("Function call"); return a + b + _state;}


The advantages of pure functions are obvious: they are easy to test, predictable, and can be safely called from parallel threads. Try to extract all logic not related to I/O into pure functions.



2. Data Immutability



Functional programming encourages working with immutable data. Instead of modifying an existing object, you create a new object with changed properties. In C#, the following are excellent for this:

  • record (starting from C# 9) — a reference type with value-based equality and immutability by default.
  • struct — for small immutable structures (e.g., coordinates, money).
  • IEnumerable<T> — for immutable collections via LINQ.


Example with record:



public record Person(string Name, int Age);

// Using a with-expression to create a copy with modificationsvar original = new Person("Alexey", 30);var updated = original with { Age = 31 };

Console.WriteLine(original); // Person { Name = Alexey, Age = 30 }Console.WriteLine(updated); // Person { Name = Alexey, Age = 31 }


This approach prevents accidental data modification in one place from affecting other parts of the program.



3. LINQ — Functional Data Queries



LINQ (Language Integrated Query) is perhaps the most prominent example of the functional approach in C#. It allows processing collections in a declarative style using method chains.



Key functional LINQ methods:

  • Select — transformation of each element (analogous to map).
  • Where — filtering (analogous to filter).
  • Aggregate — folding (analogous to reduce).
  • SelectMany — flattening nested collections (flatMap).


Example: find the sum of squares of even numbers.



int[] numbers = { 1, 2, 3, 4, 5, 6 };

// Imperative styleint sumImperative = 0;foreach (var num in numbers){ if (num % 2 == 0) { sumImperative += num * num; }}

// Functional style with LINQint sumFunctional = numbers .Where(n => n % 2 == 0) // filtering .Select(n => n * n) // transformation .Sum(); // aggregation

C

Blogs

Book Recommendations