Ever wondered how to pass methods as arguments or store functions in variables, then delegates are your new best friend! So in C#, delegates allow us to reference methods and call them dynamically, making our code more flexible and reusable. Theyโre like function pointers in C++, but type-safe and way cooler. ๐
What is a Delegate?
A delegate is a type that represents a reference to a method with a specific signature. Instead of calling methods directly, you can store them in variables and pass them around like any other object.
Types of Delegates
Func Delegate โ A built-in delegate for methods that return a value.
Action Delegate โ A built-in delegate for methods that return void.
Predicate Delegate โ A built-in delegate for methods that return a boolean.
Letโs see them in action! ๐
// Action<T> for void methods
Action<string> printAction = Console.WriteLine;
printAction("This is an Action delegate");
// Func<T, TResult> for methods that return values
Func<int, int, int> add = (x, y) => x + y;
Console.WriteLine($"Sum: {add(5, 3)}");
// Predicate<T> for methods that return a boolean
Predicate<int> isEven = num => num % 2 == 0;
Console.WriteLine(isEven(10)); // true
Logging with Delegates: A Practical Example
Now, letโs see how delegates can help us log messages dynamically using different logging mechanisms. Imagine weโre logging database operations for MongoDB and Couchbase. Instead of writing separate logging functions for each, we use delegates to make it flexible and reusable!
C# Logging with Delegates
using System;
using System.IO;
namespace DelegatesExplore
{
internal static class Program
{
private const string CouchbaseLogFilePath = "couchbase_logs.txt";
private const string MongoLogFilePath = "mongo_logs.txt";
private static readonly Action<string> PrintConsoleAction = text =>
{
Console.WriteLine($"[Console Log] {text}");
};
private static readonly Action<string> PrintToFileAction = text =>
{
using (StreamWriter writer = new StreamWriter(MongoLogFilePath, append: true))
{
writer.WriteLine($"[Mongo File Log] {DateTime.Now}: {text}");
}
};
private static readonly Action<string, bool> PrintCouchbaseLog = (message, success) =>
{
string status = success ? "Success" : "Failed";
Console.WriteLine($"[Couchbase Log] {message} - Status: {status}");
};
private static readonly Action<string, bool> PrintCouchbaseFileLog = (message, success) =>
{
string status = success ? "Success" : "Failed";
using (StreamWriter writer = new StreamWriter(CouchbaseLogFilePath, append: true))
{
writer.WriteLine($"[Couchbase File Log] {DateTime.Now}: {message} - Status: {status}");
}
};
private static void ConnectToMongo(Action<string> log)
{
log("Inserting new record");
log("The new record was inserted into MongoDB");
}
private static void ConnectToCouchbase(Action<string, bool> log)
{
log("Inserting unstructured record", true);
log("The new record was inserted into Couchbase DB", true);
}
private static void Main()
{
Console.WriteLine("Welcome to Delegates Lesson!");
// MongoDB Logging
ConnectToMongo(PrintConsoleAction);
ConnectToMongo(PrintToFileAction);
// Couchbase Logging
ConnectToCouchbase(PrintCouchbaseLog);
ConnectToCouchbase(PrintCouchbaseFileLog);
}
}
}
Why Use Delegates? ๐คฉ
Decouples method execution โ Methods donโt need to be hardcoded.
Encourages reusability โ Pass different logging strategies dynamically.
Supports functional programming โ Functions as first-class citizens!
Final Thoughts
Delegates are powerful tools that make our C# applications more flexible and maintainable. They give us a taste of functional programming while keeping the elegance of object-oriented design. So next time you need dynamic method execution, think delegates!
Happy coding! ๐