Delegates support minimal coupling between components.
Example with LINQ Where Method
The Where
method uses a delegate that determines which elements of a sequence pass the filter:
// Numbers where, for each number n, n is less than 10:
var smallNumbers = numbers.Where(n => n < 10);
The prototype for Where
:
public static IEnumerable<TSource> Where<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate);
Loose coupling is achieved because:
- There is no need to implement an interface
- There is no need to derive from a base class
Example by Building a Logger
Delegate
public static class Logger
{
public static Action<string> WriteMessage;
public static void LogMessage(string msg)
{
// The compiler generates an `Invoke` method for any delegate type declared. This one takes a single
// `string` argument and has a `void` return type.
// The `?.` here prevents a `NullReferenceException` if the delegate does not have an invocation list attached.
WriteMessage?.Invoke(msg);
// Alternatively, without this robustness, we could use:
// WriteMessage(msg);
}
}
Implementation
// This method could be static or instance.
public static class LoggingMethods
{
public static void LogToConsole(string message) { Console.Error.WriteLine(message); }
}
// Attach LogToConsole to the WriteMessage delegate:
Logger.WriteMessage += LoggingMethods.LogToConsole;
## Another Implementation
public class FileLogger
{
private readonly string logPath;
public FileLogger(string path)
{
logPath = path;
Logger.WriteMessage += LogMessage;
}
public void DetachLog() { Logger.WriteMessage -= LogMessage; }
private void LogMessage(string msg)
{
try
{
using (var log = File.AppendText(logPath))
{
log.WriteLine(msg);
log.Flush();
}
}
catch (Exception)
{
// Catch and drop the exception (can't log an exception that came from the logger!)
// If any delegate method throws an exception, the remaining delegates on the invocation list will
// not be invoked.
}
}
}
// When `FileLogger` is called, it attaches its `LogMessage` method to the `WriteMessage` delegate:
var file = new FileLogger("log.txt");