There are two parts to this.
First, you need to adjust the NoFilter()
function to be compatible with Predicate<T>
. Notice the latter is generic, but the former is not. Make NoFilter()
look like this:
private bool NoFilter<T>(T item) { return true; }
I know you never use the generic type argument, but it's necessary to make this compatible with your predicate signature.
For fun, you could also define NoFilter
this way:
private Predicate<T> NoFilter = x => true;
Now the second part: we can look at using the new generic method as the default argument for GetItems()
. The trick here is you can only use constants. While NoFilter()
will never change, from the compiler's view that's not quite the same things a a formal constant. In fact, there is only one possible constant you can use for this: null
. That means your method signature must look like this:
private List<thing> GetItems(Predicate<thing> filter = null)
Then you can check for null
at the beginning of your function and replace it with NoFilter
:
private List<thing> GetItems(Predicate<thing> filter = null)
{
if (filter == null) filter = NoFilter;
return rawList.Where(filter).ToList();
}
And if you also do want to explicitly pass this to the method when calling it, that would look like this:
var result = GetItems(NoFilter);
That should fully answer the original question, but I don't want to stop here. Let's look deeper.
Since you need the if
condition anyway now, at this point I would tend to remove the NoFilter<T>()
method entirely, and just do this:
private IEnumerable<thing> GetItems(Predicate<thing> filter = null)
{
if (filter == null) return rawList;
return rawList.Where(filter);
}
Note that I also changed the return type and removed the ToList()
call at the end. If you find yourself calling ToList()
at the end of a function just to match a List<T>
return type, it's almost always much better to change the method signature to return IEnumerable<T>
instead. If you really need a list (and usually, you don't), you can always call ToList()
after calling the function.
This change makes your method more useful, by giving you a more abstract type that will be more compatible with other interfaces, and it potentially sets you up for a significant performance bump, both in terms of lowered memory use and in terms of lazy evaluation.
One final addition here is, if you do pare down to just IEnumerable
, we can see now this method does not really provide much value at all beyond the base rawItems
field. You might look at converting to a property, like this:
public IEnumerable<T> Items {get {return rawList;}}
This still allows the consumer of your type use a predicate (or not) if they want via the existing .Where()
method, while also continuing to hide the underlying raw data (you can't directly just call .Add()
etc on this).
NoFilter
asPredicate<things> and pass it
. – SoulierGetItems() { return GetItems(NoFilter); }
– Reachnull
and you'd have to check for that in your code. Alternatively you could overload the method with a second one that doesn't take a predicate. – Dashernew Predicate<thing>(NoFIlter)
is evaluated at run time because of the constructor there so it will not work however you put it. – ArianaNoFilter
is used when no parameter is provided. They're not asking how to pass a normal delegate as a parameter to a method. – Karlottenew Predicate<thing>(NoFIlter)
is resolved entirely at compile time, but it's simply not specified in the specs as a compile time constant. – Karlottenew Predicate<thing>(NoFilter)
is resolved when the code is compiling. Now that you say it I can see how. Thanks – Ariana2 + 2
andWhat it is 2 * 2?
Same answer, two different questions. My question was about passing predicates, not about a compile time constant error. – Clyte