C sharp - Functional Programming Concepts in C#

C# is primarily an object-oriented language, but it strongly supports functional programming (FP) principles.

Functional programming focuses on:

  • Pure functions

  • Immutability

  • Higher-order functions

  • Declarative style

  • Avoiding side effects

Modern C# (especially C# 7–12) includes many FP features.


1. Pure Functions

A pure function:

  • Always returns the same output for same input

  • Has no side effects

  • Does not modify external state

Example:

int Add(int a, int b)
{
    return a + b;
}

Not pure:

int total = 0;

int Add(int a)
{
    total += a;   // modifies external state
    return total;
}

Pure functions are:

  • Predictable

  • Easy to test

  • Thread-safe


2. Immutability

In FP, data should not change after creation.

Mutable object:

class Person
{
    public string Name { get; set; }
}

Immutable object:

record Person(string Name);

Records (introduced in C# 9) are designed for immutability.

Benefits:

  • Safer concurrency

  • No unexpected state changes

  • Easier debugging


3. Higher-Order Functions

A higher-order function:

  • Takes a function as parameter

  • Returns a function

Example:

Func<int, int> square = x => x * x;

int Execute(Func<int, int> operation, int value)
{
    return operation(value);
}

Usage:

Console.WriteLine(Execute(square, 5));

This is core functional design.


4. Lambda Expressions

Lambda expressions allow inline functions:

(x, y) => x + y

Used heavily in:

  • LINQ

  • Delegates

  • Async programming

They make code more declarative.


5. LINQ (Declarative Programming)

LINQ is one of the strongest FP features in C#.

Instead of writing loops:

List<int> result = new List<int>();
foreach (var x in numbers)
{
    if (x > 5)
        result.Add(x);
}

Use LINQ:

var result = numbers.Where(x => x > 5).ToList();

This is:

  • Declarative

  • More readable

  • Functional style


6. First-Class Functions

Functions can be:

  • Assigned to variables

  • Passed as parameters

  • Returned from methods

Example:

Func<int, int, int> multiply = (a, b) => a * b;

C# treats functions as values.


7. Function Composition

Combine functions:

Func<int, int> add2 = x => x + 2;
Func<int, int> multiply3 = x => x * 3;

Func<int, int> composed = x => multiply3(add2(x));

Console.WriteLine(composed(5)); // (5+2)*3 = 21

This avoids intermediate variables.


8. Pattern Matching

Modern C# supports pattern matching:

static string Check(object obj) =>
    obj switch
    {
        int i when i > 0 => "Positive Integer",
        string s => "String",
        _ => "Unknown"
    };

Pattern matching improves:

  • Code clarity

  • Functional-style branching


9. Avoiding Null (Option-like Pattern)

Functional programming discourages nulls.

C# uses:

  • Nullable reference types

  • ?. operator

  • ?? operator

Example:

string name = user?.Name ?? "Unknown";

Some libraries implement:

  • Option

  • Maybe pattern

To eliminate null-related bugs.


10. Recursion Over Loops

Functional style often prefers recursion.

Example:

int Factorial(int n)
{
    if (n <= 1) return 1;
    return n * Factorial(n - 1);
}

Though C# doesn't optimize tail recursion fully, recursion is still supported.


11. No Shared State (Concurrency Advantage)

Immutability + pure functions:

  • Safe parallel execution

  • No race conditions

  • Easier async programming

This is why FP concepts are powerful in modern backend systems.


12. OOP vs Functional in C#

OOP Functional
Focus on objects Focus on functions
Mutable state common Prefer immutability
Behavior inside classes Behavior passed as functions
Side effects common Avoid side effects

C# supports hybrid approach.


Real-World Usage

Functional concepts are used in:

  • LINQ queries

  • Async workflows

  • Data transformation pipelines

  • Reactive programming

  • Microservices