Search code examples
c#.netlinqfunc

Compile Error 'cannot convert' on Declared Delegate


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.


Solution

  • 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));