Answering your specific question,
private static IQueryable<Contact> FilterContactList(
FilterDescriptor filter,
IQueryable<Contact> contactList,
Func<Contact, IEnumerable<string>> selector,
Predicate<string> predicate)
{
return from contact in contactList
where selector(contract).Any(predicate)
select contact;
}
In the case of "Name", you call it as;
FilterContactList(
filter,
contactList,
(contact) => new []
{
contact.FirstName,
contact.LastName,
contact.FirstName + " " + contact.LastName
},
string.StartWith);
You should add an overload as,
private static IQueryable<Contact> FilterContactList(
FilterDescriptor filter,
IQueryable<Contact> contactList,
Func<Contact, string> selector,
Predicate<string> predicate)
{
return from contact in contactList
where predicate(selector(contract))
select contact;
}
So you can call it like this for "Company" field.
FilterContactList(
filter,
contactList,
(contact) => contact.Company,
string.StartWith);
This prevents the overhead of forcing the caller to create an array when they only intend to seleect one Field/Property.
What you're probably after is something as follows
To remove that logic completely around defining the selector
and predicate
need more info on how filter is constructed. If possible filter should have the selector
and predicate
as properties for FilterContactList to use that get automatically constructed.
Expanding on that a little,
public class FilterDescriptor
{
public FilterDescriptor(
string columnName,
FilterOperator filterOperator,
string value)
{
switch (columnName)
{
case "Name":
Selector = contact => new []
{
contact.FirstName,
contact.LastName,
contact.FirstName + " " + contact.LastName
};
break;
default :
// some code that uses reflection, avoids having
// a case for every column name
// Retrieve the public instance property of a matching name
// (case sensetive) and its type is string.
var property = typeof(Contact)
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.FirstOrDefault(prop =>
string.Equals(prop.Name, columnName) &&
prop.PropertyType == typeof(string));
if (property == null)
{
throw new InvalidOperationException(
"Column name does not exist");
}
Selector = contact => new[]
{
(string)property.GetValue(contact, null)
};
break;
}
switch (filterOperator)
{
case FilterOperator.StartsWith:
Predicate = s => s.StartsWith(filter.Value);
break;
case FilterOperator.Contains:
Predicate = s => s.Contains(filter.Value);
break;
case FilterOperator.IsEqualTo:
Predicate = s => s.Equals(filter.Value);
break;
}
}
public Func<Contact, IEnumerable<string>> Selector { get; private set; }
public Func<string, bool> Predicate { get; private set; }
}
Your FilterContactList
would then become
private static IQueryable<Contact> FilterContactList(
FilterDescriptor filter,
IQueryable<Contact> contactList)
{
return from contact in contactList
where filter.Selector(contract).Any(filter.Predicate)
select contact;
}
Best Answer
It seems pretty pointless to me.
It's more code that you have to maintain - and in a year's time no one will remember the debates you had and half your code will use
string.Format
the other half will use this method.It's also distracting you from the real task of developing software that solves real problems.
You've probably wasted more money by having these discussions that it would have cost the company to buy ReSharper licenses for everyone.