I have been working with C# for quite some time but relatively new to the concepts of lambdas and Linq. I was working with a Linq To SQL example and trying to write a generic solution for executing a search against a collection of entities (eg. list of Customer
objects) where the search parameter will be specified by passing a partially filled object of the entity class itself. I was doing this just to ensure that a person does not have to go on specifying different overloads for different searches based on the entity class attributes and trying to write a generic solution which will cater to any entity class.
Hence I used reflection and an array of predicates to successively apply the Where clauses to the collection.
Client App
using (CustomerManager oCustomerManager = new CustomerManager())
{
IEnumerable<Customer> customers = oCustomerManager.Load();
Customer oSearchCustomer = new Customer();
oSearchCustomer.City = "London";
oSearchCustomer.ContactName = "Thomas Hardy";
IEnumerable<Customer> customerList = oCustomerManager.Search(oSearchCustomer);
foreach (Customer customer in customerList)
{
Console.WriteLine(customer.ToString());
}
}
Manager Class
public IEnumerable<Customer> Search(Customer searchObject)
{
IEnumerable<Customer> customers = DataContext.Customers;
List<Func<Customer, bool>> result =
DataContext.Customers.GenerateFilterClause<Customer>(searchObject);
foreach (var item in result)
{
customers = customers.Where(item);
}
return customers;
}
Extension Method Utility Class
public static class UtilityExtensions
{
public static List<Func<T, bool>> GenerateFilterClause<T>(this IEnumerable<T>
collection, T searchEntity)
{
List<Func<T, bool>> whereFilterList = new List<Func<T, bool>>();
Func<T, bool> predicate = null;
var propertyList = searchEntity.GetType().GetProperties();
foreach (PropertyInfo p in propertyList)
{
if (p.GetCustomAttributes(false).OfType<ColumnAttribute>().Count() > 0)
{
string propName = p.Name;
var searchVal =
searchEntity.GetType().GetProperty(propName).GetValue(searchEntity,null);
if (searchVal != null)
{
predicate = new Func<T, bool>(entity => propertyWhereClause(entity,
searchEntity, propName, searchVal));
whereFilterList.Add(predicate);
}
}
}
return whereFilterList;
}
private static bool propertyWhereClause<T>(T obj, T searchEntity, string propertyName, object searchVal)
{
return obj.GetType().GetProperty(propertyName).GetValue(obj,
null).Equals(searchVal);
}
}
While the solution is working, I have two specific questions:
- What are the drawbacks of this solution? I was hoping to have inputs regarding performance and cleaner way to rewrite the code.
- Can anyone suggest a more efficient and better solution? That would help me to understand the proper way to utilize the power of lambdas and Linq.