Functional Programming in C#: Advanced Techniques and Practices

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#: Advanced Level



Functional programming (FP) is a paradigm that has been actively penetrating the world of C# in recent years. Thanks to the capabilities of .NET, developers can combine object-oriented and functional approaches, creating more reliable, testable, and predictable code. In this article, we will explore advanced FP techniques in C# that will help you go beyond simple LINQ usage.



1. Pure Functions and Side Effects: Strict Control



A pure function is a function whose result depends only on its input arguments and which causes no side effects (modifying global state, input-output, exceptions). In C#, we can approach this ideal by using immutable types and avoiding parameter modification.



// Pure function: result depends only on x and ypublic static int Add(int x, int y) => x + y;

// Impure function: depends on external stateprivate static int _counter = 0;public static int IncrementCounter() => ++_counter;


At an advanced level, it is important to strictly separate pure computations from operations with side effects. For this, you can use the IO pattern (in functional languages) or its simplified analogs in C# via Func<T> and lazy evaluation.



Practical Technique: "Lazy Execution"



Instead of immediately performing an action with a side effect, return a delegate that will execute it:



public static Func<int> CreateFileReadOperation(string path){    return () => File.ReadAllText(path).Length; // Side effect is deferred}

// Usagevar operation = CreateFileReadOperation("data.txt");// ... pure logic ...int length = operation(); // Side effect is executed here


2. Function Composition and Currying



Composition is combining two or more functions to create a new one. Currying is transforming a function of several arguments into a chain of functions of one argument. These techniques make code more modular and reusable.



Composition via LINQ and Custom Methods



In C#, composition can be implemented using extension methods:



public static class FuncExtensions{    public static Func<T, TResult> Compose<T, TIntermediate, TResult>(        this Func<T, TIntermediate> first,        Func<TIntermediate, TResult> second)        => x => second(first(x));}

// Example: f(x) = x + 2, g(x) = x * 3, h = f ∘ gFunc<int, int> addTwo = x => x + 2;Func<int, int> multiplyByThree = x => x * 3;var composed = multiplyByThree.Compose(addTwo); // h(x) = (x*3) + 2Console.WriteLine(composed(5)); // 17


Currying in C#



Currying allows partial application of a function:



public static Func<int, Func<int, int>> CurriedAdd = x => y => x + y;

var addFive = CurriedAdd(5); // Partial applicationConsole.WriteLine(addFive(10)); // 15

// More complex example: logging function with a prefixpublic static Func<string, Func<string, string>> CreateLogger = prefix => message => $"[{prefix}] {message}";

var infoLogger = CreateLogger("INFO");Console.WriteLine(infoLogger("System started")); // [INFO] System started


3. Monads and Working with Option (Maybe)



A monad is a pattern that allows sequentially applying functions to values wrapped in a context (e.g., the possibility of absence of a value or asynchrony). In C#, the Option<T> or Maybe<T> implementation is popular for avoiding null.



Simple Option Implementation



public class Option<T>{    private readonly T _value;    private readonly bool _hasValue;

pri

Blogs

Book Recommendations