How to pass a predicate as parameter c# - c#

How can I pass a predicate into a method but also have it work if no predicate is passed? I thought maybe something like this, but it doesn't seem to be correct.
private bool NoFilter() { return true; }
private List<thing> GetItems(Predicate<thing> filter = new Predicate<thing>(NoFilter))
{
return rawList.Where(filter).ToList();
}

private List<thing> GetItems(Func<thing, bool> filter = null)
{
return rawList.Where(filter ?? (s => true)).ToList();
}
In this expression s => true is the fallback filter which is evaluated if the argument filter is null. It just takes each entry of the list (as s) and returns true.

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).

Related

How to change the generic type of a lambda function in C#

I am facing the following problem with conversion of the inner type in Predicate<T>. I have a class implementing a basic interface. Additionally to the interface, the class has some advanced properties and methods.
public interface IBasic { /* ... */ }
public class Advanced : IBasic { /* ... */ }
In a method I get a number of predicates over the Advanced class and I would like to sort them into two lists: 1) predicates that use only the IBasic interface 2) predicates that need all features from the Advanced class.
List<Predicate<IBasic>> basic = new List<Predicate<IBasic>>();
List<Predicate<Advanced>> advanced = new List<Predicate<Advanced>>();
public void SetPredicates(params Predicate<Advanced>[] predicates)
{
foreach(var item in predicates)
{
//Of course the `is` keyword does not work here, always returning false.
//Is it possible to do the check on the lambda function in item in a different way?
if (item is Predicate<IBasic>)
basic.Add((Predicate<IBasic>)item); //And this cast throws an exception of course.
else
advanced.Add(item);
}
}
Questions
Is it possible at all?
How can I check if the generic type of the predicate can be reduced to the IBasic interface?
How can I perform the predicate cast?
The number of predicates is low, so I am fine using slower things like reflection of dynamic types.
Background
The reason for the partition of predicates is that I have lots of Advanced instances. I want to pre-filter them first by predicates that require only the IBasic interface as those evaluate very fast. Then I will have to filter a much lower number of instances in the second pass with complex methods of Advanced (not in IBasic) since they take very long to evaluate.
you could implement an overloaded Constructor in the Predicate Class. One for Basic and the other for Advanced. Also do a bool check on the item to see it is a basic check?
also maybe you can do some sort of boolean check on some property of the item to see if it is basic
List<Predicate<IBasic>> basic = new List<Predicate<IBasic>>();
List<Predicate<Advanced>> advaned = new List<Predicate<Advanced>>();
public void SetPredicates(params Predicate<Advanced>[] predicates)
{
foreach(var item in predicates)
{
//Of course the `is` keyword does not work here, always returning false.
//Is it possible to do the check on the lambda function in item in a different way?
if (item is Predicate<IBasic>)
basic.Add(new Predicate(item, isBasic)); //And this cast throws an exception of course.
else
advanced.Add(new Predicate(item));
}
}
#PavelAnikhouski pointed me to a right direction. The issue is that contravariance would be impractical for arrays. Nevertheless, it is possible to perform the contravariant cast at compile time by omiting params.
So instead of calling:
item.SetPredicates(x => !x.Empty /*IBasic*/, x => x.IsGlobalOptimum /*Advanced*/);
it can be broken into separate calls, each being correctly recognized by the compiler:
item.AddPredicate(x => !x.Empty); //IBasic
item.AddPredicate(x => x.IsGlobalOptimum); //Advanced
The Advanced class then has two overloaded methods:
public void AddPredicate(Predicate<IBasic> p)
{
basic.Add(p);
}
public void AddPredicate(Predicate<Advanced> p)
{
advanced.Add(p);
}
This is not the best interface, it would be nicer to be able to bulk add several predicates at once, but it works. In case anyone finds a more elegant solution, I will be glad to see and discuss it.

Is there a technique for using DebugFormat() with args that are expensive to construct?

I'm a big fan of log4net and log4j's "format" API for logging messages, which avoids the cost of calling ToString() on arguments if the necessary log level is not enabled.
But there are times when one or more of the arguments I'd use is not a simple object, it needs to be constructed in some way. For example, like this:
logger.DebugFormat("Item {0} not found in {1}",
itemID,
string.Join(",", items.Select(i => <you get the idea>))
);
Is there a technique to encapsulate the second argument (the Join expression) such that it won't be executed unless DebugFormat decides that it should be (like it does for the ToString of the first argument)?
It feels like a lambda or func or something should be able to help here, but I'm fairly new to C# and I can't quite put my finger on it.
You can create extension method or wrapper class, but it's not easy to get satisfying syntax, because you want some parameters (itemID in your example) to be stated explicitly, and some to be resolved only if necessary. But you cannot pass anonymous function as object. Instead I'd use another solution which does not require extension methods or wrappers. Create class like this:
public sealed class Delayed {
private readonly Lazy<object> _lazy;
public Delayed(Func<object> func) {
_lazy = new Lazy<object>(func, false);
}
public override string ToString() {
var result = _lazy.Value;
return result != null ? result.ToString() : "";
}
}
This accepts function which returns object in constructor and will not call this function until ToString() is called, which as you know is called by log4net only if necessary (if such debugging level is enabled). Then use like this:
logger.DebugFormat("Item {0} not found in {1}",
itemID,
new Delayed(() => string.Join(",", items.Select(i => <you get the idea>)))
);

Why does this linq extension method hit the database twice?

I have an extension method called ToListIfNotNullOrEmpty(), which is hitting the DB twice, instead of once. The first time it returns one result, the second time it returns all the correct results.
I'm pretty sure the first time it hits the database, is when the .Any() method is getting called.
here's the code.
public static IList<T> ToListIfNotNullOrEmpty<T>(this IEnumerable<T> value)
{
if (value.IsNullOrEmpty())
{
return null;
}
if (value is IList<T>)
{
return (value as IList<T>);
}
return new List<T>(value);
}
public static bool IsNullOrEmpty<T>(this IEnumerable<T> value)
{
if (value != null)
{
return !value.Any();
}
return true;
}
I'm hoping to refactor it so that, before the .Any() method is called, it actually enumerates through the entire list.
If i do the following, only one DB call is made, because the list is already enumerated.
var pewPew = (from x in whatever
select x)
.ToList() // This enumerates.
.ToListIsNotNullOrEmpty(); // This checks the enumerated result.
I sorta don't really want to call ToList() then my extension method.
Any ideas, folks?
I confess that I see little point in this method. Surely if you simply do a ToList(), a check to see if the list is empty suffices as well. It's arguably harder to handle the null result when you expect a list because then you always have to check for null before you iterate over it.
I think that:
var query = (from ...).ToList();
if (query.Count == 0) {
...
}
works as well and is less burdensome than
var query = (from ...).ToListIfNotNullOrEmpty();
if (query == null) {
...
}
and you don't have to implement (and maintain) any code.
How about something like this?
public static IList<T> ToListIfNotNullOrEmpty<T>(this IEnumerable<T> value)
{
if (value == null)
return null;
var list = value.ToList();
return (list.Count > 0) ? list : null;
}
To actually answer your question:
This method hits the database twice because the extension methods provided by the System.Linq.Enumerable class exhibit what is called deferred execution. Essentially, this is to eliminate the need for constructing a string of temporarily cached collections for every part of a query. To understand this, consider the following example:
var firstMaleTom = people
.Where(p => p.Gender = Gender.Male)
.Where(p => p.FirstName == "Tom")
.FirstOrDefault();
Without deferred execution, the above code might require that the entire collection people be enumerated over, populating a temporary buffer array with all the individuals whose Gender is Male. Then it would need to be enumerated over again, populating another buffer array with all of the individuals from the first buffer whose first name is Tom. After all that work, the last part would return the first item from the resulting array.
That's a lot of pointless work. The idea with deferred execution is that the above code really just sets up the firstMaleTom variable with the information it needs to return what's being requested with the minimal amount of work.
Now, there's a flip side to this: in the case of querying a database, deferred execution means that the database gets queried when the return value is evaluated. So, in your IsNullOrEmpty method, when you call Any, the value parameter is actually being evaluated right then and there -- hence a database query. After this, in your ToListIfNotNullOrEmpty method, the line return new List<T>(value) also evaluates the value parameter -- because it's enumerating over the values and adding them to the newly created List<T>.
You could stick the .ToList() call inside the extension, the effect is slightly different, but does this still work in the cases you have?
public static IList<T> ToListIfNotNullOrEmpty<T>(this IEnumerable<T> value)
{
if(value == null)
{
return null;
}
var result = value.ToList();
return result.IsNullOrEmpty() ? null : result;
}

Cast from filtered custom List<T> with LINQ

I have a custom list which inherits from Generic.List<T> like this:
public class TransferFileList<T> : List<TransferFile> { .. }
When I set (where 'Files' is a TransferFileList<T>):
var files = uploadResponse.Files.Where(x => !x.Success).ToList()
the 'files' object resolves as System.Collections.Generic.List<TransferFile>, not TransferFileList<T>, which is what I would expect as it was what was being filtered through the Where, so how could I successfully return a list of TransferFileList<T> into 'files'?
I did try:
var files = uploadResponse.Files.Where(x => !x.Success).ToList()
as TransferFileList<TransferFile>;
but using that safe cast, it just resolves as null.
Thanks guys and gals.
First, I have to ask why you are inheriting from List<T>? 99% of the time that's a bad idea.
If you want to extend the functionality of a list, use extension methods:
public static something PrintErrors(this List<TransferFile> list)
{
//do your printing logic
}
On to the answer: ToList() operates on an IEnumerable<T> and converts the members of the sequence to a List of the same type. Since you inherit from List<T> which implements IEnumerable<T>, that's what happens there.
Where() works the same way - operates on an IEnumerable<T> and returns an IEnumerable<T>.
To get some arbitrary list-like object back, like you have, you need to add the items in a sequence to your custom list, like so:
var myFiles = new TransferFileList<TransferFile>();
myFiles.AddRange(originalFileList.Where(condition));
You can add an extension method for IEnumerable<TransferFile> to handle that scenario:
public static TransferFileList ToTransferFileList(
this IEnumerable<TransferFile> files)
{
return new TransferFileList(files);
}
// ...
var files = uploadResponse.Files.Where(x => !x.Success).ToTransferFileList();
This provides you with the TransferFileList instead of just a List<TransferFile>. Note the reason your as returns null is because while TransferFileList is a List<TransferFile>, the same does not hold in the other direction. That is, your List<TransferFile> is NOT a TransferFileList object.
I agree with #RexM that any attempt at subclassing List<T> be avoided due to the multitude of pitfalls associated. I suggest Composition (Has-A rather than Is-A) or sticking with the base class library collections instead.
Thanks guys.
I like SLV's extension approach, but is there any other straight casting approach?
If not I might just go with the reverted in-line approach I was hoping to avoid:
var transferFiles = new TransferFileList<TransferFile>();
if (files != null)
transferFiles.AddRange(files);

Can a C# lambda expression ever return void?

I have the following method, and I want to know if there is anything that can go in place default(void) below because there is a compiler error that says that void is not valid here:
private void applyDefaultsIfNecessary(ApplicationConfiguration configuration)
{
var defaults = new Dictionary<Predicate<ApplicationConfiguration>, Action<ApplicationConfiguration>>()
{
// { rule, action } - if rule is true, execute action
{ (c) => c.ConnectionString == null , (c) => c.ConnectionString = "foo" },
{ (c) => c.OutputExcelFilePath == null, (c) => c.ConnectionString = "bar" },
{ (c) => c.OutputDirectory == null, (c) => c.OutputDirectory = "baz" }
};
//Nothing to select, but we want to loop throough the dict and invoke action, if rule is true.
//It is a pity there is no extension method called DoForEach on collections.
defaults.Select((item) => item.Key.Invoke(configuration) ? item.Value.Invoke(configuration) : default(void) );
}
I realize that I can use the if-else statement instead of the ternary operator (or that I could call a dummy method to return void). Also, the Select extension method does not like lambdas that return void. It seems to say that the type cannot be inferred, but of course if I specify the type like this, either:
defaults.Select<ApplicationConfiguration, void>((item) => { if (item.Key.Invoke(configuration)) item.Value.Invoke(configuration); } );
I was curious from a language design standpoint, why we don't have expressions that can return void or the data type for variables that is void.
I refer you to section 7.1 of the specification, which states:
[An expression may be classified as]
"nothing". This occurs when the
expression is an invocation of a
method with a return type of void.
An expression classified as nothing is only valid in the context of a
statement expression.
[Emphasis added].
That is to say that the only time you may use an expression which is a void-returning method invocation is when the expression makes up an entire statement. Like this:
M();
This is, in effect, a violation of functional programming rules. This has the same flaw Eric Lippert described about List.ForEach: You're philosphically trying to cause side effects on your collection.
Enumerable.Select is intended to return a new collection - filtering the input. It is not intended to execute code.
That being said, you can work around this by doing:
defaults.Where(item => item.Key.Invoke(configuration)).ToList().ForEach( item => item.Value.Invoke(configuration));
It's just not as clear as doing:
var matches = defaults.Where(item => item.Key.Invoke(configuration));
foreach(var match in matches)
match.Value.Invoke(configuration);
Firstly, you should really avoid putting side-effects in standard linq query operators, and secondly this won't actually work since you aren't enumerating the Select query anywhere. If you want to use linq you could do this:
foreach(var item in defaults.Where(i => i.Key.Invoke(configuration)))
{
item.Value.Invoke(configuration);
}
Regarding your question, I'm pretty sure there are no possible values of void and you can't return it explicity. In functional languages such as F#, void is replaced with 'unit' i.e. a type with only one possible value - if you wanted you could create your own unit type and return that. In this case you could do something like this:
defaults.Select(item => {
if(item.Key.Invoke(configuration))
{
item.Value.Invoke(configuration);
}
return Unit.Value;
}).ToList();
But I really can't recommend doing this.
From a language standpoint, void means "does not exist", which begs the question: what value would there be in declaring a variable that does not exist?
The problem here is not a language limitation but the fact that you're using a construct (the ternary operator) that demands two rvalues -- where you only have one.
If I may be blunt, I'd say you're avoiding if/else in favor of pointless brevity. Any tricks you come up with to replace default(void) will only serve to confuse other developers, or you, in the future, long after you've stopped bothering with this sort of thing.
default doesn't work with void; but it works with a type. The Action class produces no result, but the Func<> object always has to return a result. Whatever item.Value.Invoke() returns just return the default of that, as in:
default(object)
or if it's a specific type:
default(SomeType)
Like that.

Categories