Reputation: 5651
I have a simple class with many DateTime
properties:
public class MyClass
{
public DateTime Created {get; set;}
public DateTime LastChanged {get; set;}
public DateTime LastAccessed {get; set;}
...
}
Later, somewhere in my code I would like to filter collection of MyClass
based on these properties. For each property I would like to do something like this:
myQueryableOfMyClass = myQueryableOfMyClass.Where(a => ((begin == null) || (a.Created >= begin)) && ((end == null) || (a.Created <= end));
If I had to do this for each of my DateTime
property, it would be a lot of code with some risk of a typo, so I would like to do something like this:
myQueryableOfMyClass = Filter(myQueryableOfMyClass, begin, end, MyClass.Created);
myQueryableOfMyClass = Filter(myQueryableOfMyClass, changebegin, changeend, MyClass.LastChanged);
myQueryableOfMyClass = Filter(myQueryableOfMyClass, accbegin, accend, MyClass.LastAccessed);
...
where the Filter
method is implemented using the LINQ Where
as in the first example.
The code above does not compile, of course, because MyClass.Created
is a nonsense.
There must be some solution using reflection, but I have little very experience with reflection. Could you please help me?
Upvotes: 1
Views: 322
Reputation: 31
I am a big fan of readable code where method names explain what they do. For that reason I would suggest adding the following methods. They could be either added in the data class itself as in my example or they could be in a "Filter" class.
public class MyClass
{
public DateTime Created { get; set; }
public DateTime LastChanged { get; set; }
public DateTime LastAccessed { get; set; }
public bool WasCreatedInTimespan(DateTime? begin, DateTime? end)
{
return IsDateInTimespan(Created, begin, end);
}
public bool WasChangedInTimespan(DateTime? begin, DateTime? end)
{
return IsDateInTimespan(LastChanged, begin, end);
}
public bool WasAccessedInTimespan(DateTime? begin, DateTime? end)
{
return IsDateInTimespan(LastAccessed, begin, end);
}
private static bool IsDateInTimespan(DateTime date, DateTime? begin, DateTime? end)
{
return (!begin.HasValue || date >= begin.Value) && (!end.HasValue || date >= end.Value);
}
}
With these methods, the calling code becomes very clear. Like so:
var createdList = myQueryableOfMyClass.Where(m => m.WasCreatedInTimespan(begin, end));
var changedList = myQueryableOfMyClass.Where(m => m.WasChangedInTimespan(begin, end));
var accessedList = myQueryableOfMyClass.Where(m => m.WasAccessedInTimespan(begin, end));
Upvotes: 3
Reputation: 34421
Create a helper method
public void test()
{
myQueryableOfMyClass = myQueryableOfMyClass.Where(a => Filter(begin, end, a));
}
public Boolean Filter(DateTime begin, DateTime end, DateTime date)
{
if(((begin == null) || (date >= begin)) && ((end == null) || (date <= end)))
{
return true;
}
else
{
return false;
}
}
}
Upvotes: 1
Reputation: 109567
You could use a Func<MyClass, DateTime>
to choose which property to use, like so:
public static IEnumerable<MyClass> Filter
(
IEnumerable<MyClass> myClasses,
DateTime? begin,
DateTime? end,
Func<MyClass, DateTime> selector
)
{
return myClasses.Where(a => ((begin == null) || (selector(a) >= begin)) && ((end == null) || (selector(a)) <= end));
}
You'd call it like this:
Filter(myClasses, begin, end, myClass => myClass.Created);
Where you would replace myClass => myClass.Created
with a selector for the property you want to use.
Upvotes: 4