Fading Coder

One Final Commit for the Last Sprint

Home > Notes > Content

C# Programming Fundamentals: Type Inference, Extension Methods, Delegates, Lambda Expressions, and LINQ

Notes May 14 1

Type Inference with var

The var keyword enables type inference for local variables only, not for class members. Variables declared with var must be initialized during declaration and cannot be assigned null values. The var keyword doesn't represent a new data type but serves as syntactic sugar for variables whose types can be inferred at compile time. From the IL perspective, there's no difference between using var and explicit type declarations.

Anonymous Types

Anonymous types allow creating objects without defining a formal class structure:

var personData = new
{
    FullName = "John Smith",
    YearsOld = 30,
    Department = "Engineering"
};

These types are particularly useful for temporary data structures and projections.

Extension Methods

Extension methods must be defined within static classes and are themselves static methods. When a class method conflicts with an extension method name, the class method takes precedence. The first parameter uses the this modifier to indicate which type receives the extension. This parameter represents the instance being extended. Extension methods support overloading but should be used judiciously.

They're especially valuible when extending sealed classes without modifying their source code.

Syntax Examples

public static int CalculateAverage(this int total)
{
    return total / 5;
}

public static string FormatGreeting(this string userName)
{
    return string.Format("Hello {0}, your average score is: ", userName);
}

public static string WelcomeStudent(this Student student)
{
    return "Welcome: " + student.StudentName;
}

public static string WelcomeStudent(this Student student, int years)
{
    return string.Format("Name: {0}, Age: {1}", student.StudentName, years);
}

Delegates

Delegates function as special data types that hold references to methods. They operate like function pointers, allowing method references to be stored in variables.

Implementation Steps

  1. Declare the delegate (typically outside class scope)
  2. Create methods matching the delegate signature
  3. Instantiate the delegate with a target method
  4. Invoke methods through the delegate
  5. Modify associated methods dynamically using += and -= operators
// Delegate declaration
public delegate int ArithmeticOperation(int x, int y);

static int Sum(int x, int y)
{
    return x + y;
}

static int Difference(int x, int y)
{
    return x - y;
}

static void Execute()
{
    ArithmeticOperation calculator = new ArithmeticOperation(Sum);
    int result = calculator(15, 25);
    Console.WriteLine($"15+25={result}");

    calculator -= Sum;
    calculator += Difference;

    result = calculator(15, 25);
    Console.WriteLine($"15-25={result}");
}

Anonymous Methods

Anonymous methods provide inline function definitions without explicit naming:

static void Execute()
{
    ArithmeticOperation calculator = delegate(int x, int y)
    {
        return x + y;
    };
    int result = calculator(15, 25);
    Console.WriteLine($"15+25={result}");
}

Lambda Expressions

Lambda expressions use the => operator for concise functon definitions:

static void Execute()
{
    ArithmeticOperation calculator = (int x, int y) => { return x + y; };
    int result = calculator(15, 25);
    Console.WriteLine($"15+25={result}");
}

static void SquareExample()
{
    Func<int, int> square = x => x * x;
    int result = square(15);
    Console.WriteLine($"Square of x={result}");
}

When parameters are singular, parentheses can be omitted. For single-expression bodies, braces and return statements can be removed.

Language Integrated Query (LINQ)

LINQ variants include:

  • LINQ to Objects: Object collection queries
  • LINQ to XML: XML document queries
  • LINQ to ADO.NET: Database queries
    • LINQ to Entities: Modern database integration

Traditional vs LINQ Approach

Without LINQ:

static void TraditionalApproach()
{
    int[] numbers = { 1, 7, 2, 6, 5, 4, 9, 13, 20 };
    List<int> oddNumbers = new List<int>();
    foreach (int item in numbers)
    {
        if (item % 2 != 0)
            oddNumbers.Add(item);
    }
    oddNumbers.Sort();
    oddNumbers.Reverse();
    foreach (int item in oddNumbers)
    {
        Console.WriteLine(item);
    }
}

With LINQ:

static void LinqApproach()
{
    int[] numbers = { 1, 7, 2, 6, 5, 4, 9, 13, 20 };

    var oddNumbers = from num in numbers
                     where num % 2 != 0
                     orderby num descending
                     select num;

    foreach (int item in oddNumbers)
    {
        Console.WriteLine(item);
    }
}

LINQ Standard Methods

Select Method

The Select() extension method transforms elements using a delegate:

static void TransformExample()
{
    int[] numbers = { 1, 7, 2, 6, 5, 4, 9, 13, 20 };

    var squares = numbers.Select(element => element * element);
    foreach (int item in squares)
    {
        Console.WriteLine(item);
    }
}

Where Method

The Where() method filters elements based on boolean conditions:

static void FilterExample()
{
    int[] numbers = { 1, 7, 2, 6, 5, 4, 9, 13, 20 };

    var evenSquares = numbers
                        .Where(element => element % 2 == 0)
                        .Select(x => x * x);
}

Ordering Methods

OrderBy() sorts ascending, OrderByDescending() sorts descending:

static void SortExample()
{
    int[] numbers = { 1, 7, 2, 6, 5, 4, 9, 13, 20 };

    var sortedResult = numbers
                        .Where(element => element % 2 == 0)
                        .Select(x => x * x)
                        .OrderBy(element => element);
}

static void StringSortExample()
{
    string[] names = { "Alice", "Bob", "Charlie", "David" };

    var orderedNames = names
                        .Where(element => element.Length == 2)
                        .OrderByDescending(element => element.Substring(0, 1));
}

GroupBy Method

Groups elements by specified criteria:

static void GroupExample()
{
    string[] names = { "Smith", "Johnson", "Williams", "Brown" };

    var groupedNames = names
                        .Where(element => element.Length == 5)
                        .GroupBy(element => element.Substring(0, 1));

    foreach (var group in groupedNames)
    {
        Console.WriteLine($"Group Key: {group.Key}");
        foreach (var item in group)
        {
            Console.WriteLine(item);
        }
    }
}

Query Execution

LINQ employs deferred execution - queries execute when enumerated, not when defined. Use aggregation methods like Count() to force immediate execution.

Query Syntax Variants

Method syntax with fluent interfaces:

var result = numbers
              .Where(element => element % 2 == 0)
              .Select(x => x * x)
              .OrderByDescending(x => x);

Query syntax resmebling SQL:

var result = from num in numbers
             where num % 2 == 0
             orderby num descending
             select num * num;

Advanced Query Operations

Aggregation Methods

Count, Max, Min, Average, and Sum provide statistical operations:

var count = students.Where(s => s.Id > 1010).Count();
var maxAge = students.Select(s => s.Age).Max();
var avgAge = students.Select(s => s.Age).Average();

Composite Sorting

ThenBy() provides secondary sorting criteria:

var sortedStudents = students
                      .OrderBy(s => s.Name)
                      .ThenBy(s => s.Age)
                      .ThenBy(s => s.Id);

Sequence Operations

Take(n) retrieves n elements, Skip(n) bypasses n elements:

var subset = numbers.Skip(2).Take(3);
var conditionalTake = numbers.TakeWhile(x => x % 2 != 0);
var conditionalSkip = numbers.SkipWhile(x => x < 5);

Generation Methods

Range() and Repeat() create sequences:

var sequence = Enumerable.Range(1, 10);
var repeated = Enumerable.Repeat("Hello", 5);

Distinct Values

Distinct() removes duplicate elements:

int[] numbers = { 1, 2, 2, 3, 3, 4 };
var unique = numbers.Distinct();
Tags: C#LINQ

Related Articles

Designing Alertmanager Templates for Prometheus Notifications

How to craft Alertmanager templates to format alert messages, improving clarity and presentation. Alertmanager uses Go’s text/template engine with additional helper functions. Alerting rules referenc...

Deploying a Maven Web Application to Tomcat 9 Using the Tomcat Manager

Tomcat 9 does not provide a dedicated Maven plugin. The Tomcat Manager interface, however, is backward-compatible, so the Tomcat 7 Maven Plugin can be used to deploy to Tomcat 9. This guide shows two...

Skipping Errors in MySQL Asynchronous Replication

When a replica halts because the SQL thread encounters an error, you can resume replication by skipping the problematic event(s). Two common approaches are available. Methods to Skip Errors 1) Skip a...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.