Reputation: 137
I'm having issues when passing a delegate as a Where parameter in LINQ.
I'm declaring a delegate in the namespace:
public delegate bool FilterInt<in T>(T x);
I've made a method to assign to the delegate and then assign it:
public static bool FilterData(int val)
{
if (val < 10)
return true;
return false;
}
When I try to filter a List using the delegate I get a compile time error 'Cannot conver from FilterInt to Func<Int, bool>:
listInt.Where(_filterer);
However, I can use the below (an implied delegate?) without any issues:
listInt.Where(FilterData);
I have the same issue with _comparer when I follow the MSDN doc on delegates here if I define my own delegate in the namespace as per the below:
public delegate int Comparison<in T>(T x, T y);
public static int CompareLength(string left, string right) =>
right.Length.CompareTo(left.Length);
readonly Comparison<string> _comparer = CompareLength;
list.Sort(_comparer);
However, if I omit the initial declaration of Comparison, it works fine (note - Comparison exists in the System namespace).
I assume it's an issue with my initial delegate declaration.
Upvotes: 0
Views: 355
Reputation: 338
The error occurs because of the where
clause expects a Func<TSource, TResult>
with a Boolean as TResult
and not just a Func<int>
as its representative.
IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
The closest way to use it as you wish will be something like this, but I don't believe it as a good implementation.
using System;
using System.Collections.Generic;
using System.Linq;
public delegate Func<T1, T2> FilterInt<in T1, out T2>(T1 value);
namespace DelegateTest
{
class Program
{
private static readonly List<int> List = new List<int> {0, 1, 2, 10, 11, 12};
static void Main(string[] args)
{
FilterInt<int, bool> filterInt = FilterData;
var result = List.Where(x => filterInt.Invoke(x).Invoke(x));
foreach (var item in result) Console.WriteLine(item.ToString());
}
private static Func<int, bool> FilterData(int value) => _ => value < 10;
}
}
Upvotes: 1
Reputation: 142233
Enumerable.Where
accepts Func<TSource, bool>
delegate. If you look for documentation on Func<T,TResult>
you will find out that it is declared as:
public delegate TResult Func<in T,out TResult>(T arg);
So you will need to "convert" your delegate into instance of Func<TSource, bool>
which is possible either with direct creation an instance of the delegate:
new[] { 1 }.Where(new Func<int, bool>(_filterer));
Or with anonymous (lambda) function:
new[] { 1 }.Where(i => _filterer(i));
Which is actually a syntactic sugar transformed by compiler into something like this:
// generated class to hold your lambda:
[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
public FilterInt<int> _filterer;
// your lambda:
internal bool <M>b__0(int i)
{
return _filterer(i);
}
}
// instantiation of new Func<int, bool>
Enumerable.Where(array, new Func<int, bool>(<>c__DisplayClass0_.<M>b__0));
Method group call (listInt.Where(FilterData);
) also is syntactic sugar expanded by compiler into creation of new delegate:
Enumerable.Where(array, new Func<int, bool>(FilterData));
Upvotes: 1
Reputation: 1
You can call like this.
Where(new Func<int, bool>(FilterInt))
Or
.Where(x => FilterInt(x))
Upvotes: 1