Mastering C# Part 3.2 Methods (Part-2)
Anonymous , Partial, Extension, Local Methods, Delegates, Predicates, Actions, Func

Anonymous Method
An anonymous method in C# is a method without a name, defined using the delegate keyword. It allows you to create inline methods, primarily useful in scenarios where a method implementation is required only once, such as for short event-handling or callback operations.
Syntax
delegate(parameter_list)
{
// Method body
};
Anonymous methods must be assigned to a delegate type variable or used directly as a parameter for a method that expects a delegate.
using System;
class Program
{
delegate int Operation(int x, int y); // Delegate definition
static void Main()
{
// Assigning an anonymous method to a delegate
Operation add = delegate (int a, int b)
{
return a + b;
};
int result = add(5, 3);
Console.WriteLine($"The sum is: {result}"); // Output: The sum is: 8
}
}
Key Characteristics
Inline Declaration: Anonymous methods are defined inline where they are used.
Access to Outer Variables: Anonymous methods can capture variables from the outer scope, known as closures.
Event Handlers: Often used to simplify event handling code.
Using Anonymous Methods in Event Handling
Instead of defining a separate method for event handling, you can use an anonymous method directly:
using System;
class Program
{
static void Main()
{
Action<string> print = delegate (string message)
{
Console.WriteLine(message);
};
print("Hello, World!"); // Output: Hello, World!
}
}
Capturing Variables (Closures)
Anonymous methods can capture and use variables from the scope in which they are defined:
using System;
class Program
{
delegate void PrintDelegate();
static void Main()
{
int count = 10;
// Anonymous method capturing the outer variable 'count'
PrintDelegate print = delegate
{
Console.WriteLine($"Count is: {count}");
};
print(); // Output: Count is: 10
count = 20;
print(); // Output: Count is: 20 (shows the updated value)
}
}
Comparison with Lambda Expressions
Lambda expressions were introduced in C# 3.0 as a more concise alternative to anonymous methods.
Anonymous Method:
delegate (int a, int b)
{
return a + b;
};
Lambda Expression (Preferred):
(a, b) => a + b;
Key Differences:
Syntax: Lambda expressions have a shorter, more concise syntax.
Flexibility: Lambdas support advanced features such as expression trees and type inference.
Preference: Lambdas are generally preferred over anonymous methods for modern C# development.
Anonymous Methods and Delegates
Anonymous methods are tightly coupled with delegates. For example:
using System;
class Program
{
delegate void GreetDelegate(string name);
static void Main()
{
GreetDelegate greet = delegate (string name)
{
Console.WriteLine($"Hello, {name}!");
};
greet("John"); // Output: Hello, John!
}
}
Limitations of Anonymous Methods
No Named Reusability: Anonymous methods cannot be reused elsewhere since they lack a name.
Reduced Readability: Overusing anonymous methods can make code harder to understand.
Verbose: Compared to lambda expressions, anonymous methods are more verbose.
When to Use Anonymous Methods
Event Handling: When a short, one-time-use method is needed for an event.
Temporary Delegates: For scenarios where defining a named method would be overkill.
Testing and Prototyping: Quick method implementations during development.
Partial Methods in C
Partial methods allow optional method declarations and implementations in partial classes or partial structs. These methods enable flexibility when splitting a class across multiple files, commonly used in scenarios like auto-generated code.
Key Points
Declaration and Implementation:
Declared in one part of the
partialclass.Optionally implemented in another part.
If not implemented, the declaration is removed during compilation.
Rules:
Must be
private(default access).Cannot have a return type (must be
void).Cannot be
virtual,abstract, orextern.
No Implementation? No Overhead!
- Unimplemented partial methods are ignored by the compiler.
Declaration and Call:
partial class Employee
{
partial void OnCreated(); // Declared
}
partial class Employee
{
partial void OnCreated() // Implemented
{
Console.WriteLine("Employee created.");
}
public void Create()
{
OnCreated();
}
}
Usage:
Employee emp = new Employee();
emp.Create(); // Output: Employee created.
Benefits
Decoupling: Separates declarations from implementations.
Extensibility: Useful for generated code customization.
Compiler Optimization: No performance cost for unimplemented methods.
Partial methods are a great feature for writing flexible, maintainable, and extensible code, especially in collaborative or tool-generated environments.
Extension Methods in C
Extension methods allow you to add new methods to existing types without modifying their source code or creating derived types. These are static methods that act as if they were instance methods on the extended type.
Key Points
Defined in static classes.
The first parameter specifies the type to extend, prefixed with the
thiskeyword.Commonly used to extend framework or library classes.
public static class StringExtensions
{
public static bool IsPalindrome(this string str)
{
if (string.IsNullOrEmpty(str)) return false;
return str.SequenceEqual(str.Reverse());
}
}
class Program
{
static void Main()
{
string word = "madam";
Console.WriteLine(word.IsPalindrome()); // Output: True
}
}
Local Methods in C
Local methods are methods declared inside another method. They are useful for organizing code and are accessible only within the containing method.
Key Points
Declared inside another method.
Can capture and use variables from the enclosing method.
Provide better readability and encapsulation.
class Program
{
static void Main()
{
int Factorial(int number) // Local method
{
if (number <= 1) return 1;
return number * Factorial(number - 1);
}
Console.WriteLine(Factorial(5)); // Output: 120
}
}
Comparison
| Feature | Extension Methods | Local Methods |
| Scope | Available globally to the extended type | Limited to the enclosing method |
| Usage | Adds functionality to existing types | Encapsulates logic within a method |
| Declared In | Static classes | Any method |
Both extension and local methods improve code readability and modularity, offering flexibility for different scenarios.
Delegates
A delegate is a type-safe function pointer in C#. It encapsulates references to methods and allows methods to be passed as parameters, stored as variables, or invoked dynamically.
Key Features
Type-safe: Ensures that the method signature matches the delegate signature.
Multicast: Can invoke multiple methods if combined.
Declaration and Usage
Define a Delegate:
delegate void MyDelegate(string message);Assign a Method to the Delegate:
void SayHello(string message) => Console.WriteLine($"Hello, {message}!"); MyDelegate del = SayHello; del("World"); // Output: Hello, World!Multicast Delegate:
void SayGoodbye(string message) => Console.WriteLine($"Goodbye, {message}!"); del += SayGoodbye; del("World"); // Output: // Hello, World! // Goodbye, World!
Why Use Delegates?
Decouple methods from execution logic.
Enable callbacks and event-driven programming.
Predicates
A Predicate is a pre-defined delegate type in C# used specifically for methods that take one parameter and return a boolean (bool). It's often used for testing conditions.
Signature
public delegate bool Predicate<T>(T obj);
Practical Example
using System;
using System.Collections.Generic;
class Program
{
static bool IsEven(int number) => number % 2 == 0;
static void Main()
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
// Use Predicate with FindAll
Predicate<int> predicate = IsEven;
List<int> evenNumbers = numbers.FindAll(predicate);
Console.WriteLine(string.Join(", ", evenNumbers)); // Output: 2, 4
}
}
Action
Action is a pre-defined delegate type that represents a method that does not return a value. It can take up to 16 parameters.
Signature
public delegate void Action<T1, T2, ...>();
Example
using System;
class Program
{
static void PrintMessage(string message) => Console.WriteLine(message);
static void Main()
{
Action<string> action = PrintMessage;
action("Hello, Action!"); // Output: Hello, Action!
}
}
Common Use Case
Use Action when performing operations like logging, printing, or modifying objects without returning a result.
Func
Func is a pre-defined delegate type that represents a method with a return value. It can take up to 16 input parameters, and the last type parameter specifies the return type.
Signature
public delegate TResult Func<T1, T2, ..., TResult>();
Example
using System;
class Program
{
static int Add(int x, int y) => x + y;
static void Main()
{
Func<int, int, int> func = Add;
int result = func(3, 4);
Console.WriteLine(result); // Output: 7
}
}
Detailed Comparison
| Feature | Purpose | Parameters | Return Type |
| Delegate | General method reference | Customizable | Customizable |
| Predicate | Testing conditions | Single (T) | bool |
| Action | Perform operations without return | 0 to 16 | void |
| Func | Perform operations with return | 0 to 16 | Customizable |
Deep Dive Examples
Using Delegates for Callbacks
using System;
delegate void ProcessData(int value);
class Program
{
static void PrintDouble(int value) => Console.WriteLine(value * 2);
static void PrintSquare(int value) => Console.WriteLine(value * value);
static void Main()
{
ProcessData process = PrintDouble;
process += PrintSquare;
Console.WriteLine("Processing 5:");
process(5);
// Output:
// 10
// 25
}
}
Using Action with Lambda Expressions
using System;
class Program
{
static void Main()
{
Action<string> greet = name => Console.WriteLine($"Hi, {name}!");
greet("Alice"); // Output: Hi, Alice!
}
}
Using Func to Chain Operations
using System;
class Program
{
static void Main()
{
Func<int, int, int> multiply = (x, y) => x * y;
Func<int, int> addTen = result => result + 10;
int result = multiply(3, 4); // 12
result = addTen(result); // 22
Console.WriteLine(result); // Output: 22
}
}
Using Predicate with Anonymous Methods
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
Predicate<int> isOdd = num => num % 2 != 0;
List<int> oddNumbers = numbers.FindAll(isOdd);
Console.WriteLine(string.Join(", ", oddNumbers)); // Output: 1, 3, 5
}
}
Key Points to Remember
Delegates are powerful for callbacks, event handling, and decoupling code.
Predicate is ideal for conditions, especially with LINQ and collections.
Action is useful for operations without a return value.
Func is versatile for operations that return a value.
