C# Delegates

Un delegado es un placeholder para un método. Permite pasar una función como parámetro a un método.

Hay varios tipos de delegado:

  • Action<T> consume una clase, devuelve void Ejemplo Console.WriteLine();
  • Predicate<T> consume una clase, devuelve bool Por ejemplo para abstraer condiciones
  • Func<T, K> consume una clase y devuelve otra. Por ejemplo para abstraer mappings

Usaremos el struct Book para todos los ejemplos

public struct Book
{
	public string Title;        // Title of the book.
	public string Author;       // Author of the book.
	public decimal Price;       // Price of the book.
	public bool Paperback;      // Is it paperback?

	public Book(string title, string author, decimal price, bool paperBack)
	{
		Title = title;
		Author = author;
		Price = price;
		Paperback = paperBack;
	}
}

Action (Consumer)

Tenemos el ejemplo BookDBActionService

public class BookDBActionService
{
	// List of all books in the database
	List<Book> list = new List<Book>();

	// initialize test data on constructor
	public BookDBActionService()
	{
		list.Add(new Book("title1", "author1", 10, true));
		list.Add(new Book("title2", "author2", 20, false));
	}

	// Aqui tenemos el Action<Book> donde delegamos como se procesa cada libro
	public void ProcessPaperbackBooks(Action<Book> processBook)
	{
		foreach (Book b in list)
		{
			if (b.Paperback)
			{
				// delegate call
				processBook(b);
			}
		}
	}
}

Llamada donde ejecutamos el código y llamamos al Action<Book>

public static void Main(string[] args)
{
var bookDBAction = new BookDBActionService();
bookDBAction.ProcessPaperbackBooks(book => Console.WriteLine(book.Title));
}

Predicate (Condition)

public class BookDBPredicateService
{
	// List of all books in the database
	List<Book> list = new List<Book>();

	// initialize test data on constructor
	public BookDBPredicateService()
	{
		list.Add(new Book("title1", "author1", 10, true));
		list.Add(new Book("title2", "author2", 20, false));
	}

	// Aqui tenemos el Predicate<Book> con el condicional de cada libro
	public void ProcessPaperbackBooks(Predicate<Book> processBook)
	{
		foreach (Book book in list)
		{
			// delegate call			
			if (processBook.Invoke(book))
			{
				Console.WriteLine($"    book title {book.Title}");
			}
		}
	}
}

Llamada donde ejecutamos el código y llamamos al Predicate<Book>

public static void Main(string[] args)
{
var bookDBPredicate = new BookDBPredicateService();
bookDBPredicate.ProcessPaperbackBooks(book => !book.Paperback);
}

Func

public class BookDBFuncService
{
	// List of all books in the database
	List<Book> list = new List<Book>();

	// initialize test data on constructor
	public BookDBFuncService()
	{
		list.Add(new Book("title1", "author1", 10, true));
		list.Add(new Book("title2", "author2", 20, false));
	}

	// Aqui tenemos el Func<Book, string> donde mapeamos cada libro
	public List<string> ProcessPaperbackBooks(Func<Book, string> processBook)
	{
		var fields = new List<string>();
		foreach (Book b in list)
		{
			if (b.Paperback)
			{
				// delegate call
				fields.Add(processBook(b));
			}
		}
		return fields;
	}
}

Llamada donde ejecutamos el código y llamamos al Func<Book, string>

public static void Main(string[] args)
{
var bookDBFunc = new BookDBFuncService();
var extractedFields = bookDBFunc.ProcessPaperbackBooks(book => book.Title);
}