visit
// definition
List<TOut> Map<TIn, TOut>(List<TIn> list, Func<TIn, TOut> mapper)
{
var newList = new List<TOut>();
foreach (var item in list)
{
var newItem = mapper(item);
newList.Add(newItem);
}
return newList;
}
// usage
var myList = new List<int> { 1, 2, 3, 4, 5 };
int multiplyBy2 (int num) => num * 2;
var multipliedList = Map(myList, multiplyBy2);
// output { 2, 4, 6, 8, 10 };
bool isEven (int num) => num % 2 == 0;
var isEvenList = Map(myList, isEven);
// output { false, true, false, true, false };
Func<int, int> Add(int a) => (int b) => a + b;
var add9 = Add(9);
var sum1 = add9(1);
// output 10
var sum2 = add9(2);
// output 11
public interface IProductRepository
{
int Create(Product product);
bool Update(Product product);
bool Delete(int id);
Product GetById(int id);
IEnumerable<Product> GetAll();
IEnumerable<Product> GetByCategoryId(int categoryId);
IEnumerable<Product> GetActive();
// etc...
}
As you can see in this typical example, there are numerous definitions that all return IEnumerable<Product>
. Every time you need another specific type of product filter, that requires adding to the interface and writing an entirely new implementation. That's not great for maintainability...
Instead, using higher-order functions, we can define a single method that gets IEnumerable<Product>
that takes a filter function as an input. That way, the client is free to define their own filters, and the ProductRepository doesn't need to keep being updated with new implementations.
interface IProductRepository
{
// create, update, delete omitted
IEnumerable<Product> Get(Func<Product, bool> filter = null);
}
public class ProductRepository : IProductRepository
{
private readonly List<Product> _products = new List<Product>(); // data source
public IEnumerable<Product> Get(Func<Product, bool> filter = null)
{
// typically you might use the LINQ Where method here
// but using the foreach to be clear what is happening
if (filter is null) return _products;
var filteredList = new List<Product>();
foreach(var product in _products)
{
if(filter(product))
{
filteredList.Add(product);
}
}
return filteredList;
}
}
// client code
var allProducts = _productRepository.Get();
var productsByCategoryId = _productRepository.Get(p => p.CategoryId == 1);
var activeProducts = _productRepository.Get(p => p.Active);
Also published on .