c# - 无法将 lambda 表达式转换为委托类型;但这适用于列表功能

c# - Cannot convert lambda expression to delegate type; but this works in List functions

为什么当我在自定义方法的谓词参数中传递 lambda 表达式(即 p => p.Damage)时,定义如下:

public static void Sort(T[] input, int low, int high, Func<T, bool> predicate) { do_something() }

抛出 "cannot convert lambda expression to delegate type" 异常,而列表 class' 函数中发生完全相同的事情,即

intList = new List<int>() { 1000, 9102, 123, 41, 10, 52, 24, 8, 26 };
int i = intList.FirstOrDefault(b => b > 25);

为什么这不会引发错误,而这会引发错误?

Sort(intList.ToArray(), 0, 9, i => i > 25);

我的函数中传递的谓词参数看起来与 FirstOrDefalt 函数中的谓词参数完全一样!我真的需要为我的方法明确声明 lambda 表达式是一个 Func,还是我真的需要为我希望工作完全相同的东西创建一个匿名委托?这对我来说没有任何意义,因为 FirstOrDefault 签名绝对为零,表明它允许 Lambda 表达式,它所期望的只是一个 Func 委托,它与我正在做的完全一样。

这个有效:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main( string[] args )
        {
            var intList = new List<int> { 1000, 9102, 123, 41, 10, 52, 24, 8, 26 };
            intList.ToArray()
                   .Sort( 0, 100, x => x > 27 );
        }
    }

    public static class Ex
    {
        public static void Sort<T>( this T[] input, int low, int high, Func<T, bool> predicate )
        {
            input.ToList()
                 .ForEach( x => predicate( x ) );
        }
    }
}

编辑:

这是有效的,因为定义的谓词“predicate”表示一个以 T 的对象作为参数并返回布尔值的函数。我所做的就是创建一个与定义的谓词匹配的匿名函数……

我无法解释为什么或什么在 Schalks 代码中不起作用,因为我不知道他的代码...

编辑 2(添加完整代码示例):

如果您正在使用 List 的 Sort(int index, int count, IComparer comparer) 方法,您需要一个 IComparer 实例来比较列表项。如果您希望能够将比较器指定为 lambda 表达式,则需要一个 class 实现 IComparer,它在内部使用 lambda 表达式来比较项目。 (或者对于 .net 4.5,您可以使用 Comparer<T>.Create Method 。)

这是一个完整的示例:

public class Program
{
    public static void Main( string[] args )
    {
        var idiots = new List<Idiot>
        {
            new Idiot { Weapons = new[] { new Weapon { Damage = 10 }, new Weapon { Damage = 20 } } },
            new Idiot { Weapons = new[] { new Weapon { Damage = 6 }, new Weapon { Damage = 100 } } },
            new Idiot { Weapons = new[] { new Weapon { Damage = 45 }, new Weapon { Damage = 12 } } },
            new Idiot { Weapons = new[] { new Weapon { Damage = 24 }, new Weapon { Damage = 5 } } },
        };

        foreach ( var i in idiots )
            i.Weapons.QuickSort( 0, i.Weapons.Count() - 1, ( a, b ) => a.Damage.CompareTo( b.Damage ) );

        //Solution using IEnumerable{T} extension methods
        idiots.ForEach( x => x.Weapons = x.Weapons.OrderBy( y => y.Damage ).ToArray() );
    }
}

public static class Ex
{
    public static void QuickSort<T>(this IEnumerable<T> input, int low, int high, Func<T, T, Int32> comparer)
    {
        input
            .ToList()
            .Sort( low, high, new FunctionalComparer<T>( comparer ) );
    }
}

public class FunctionalComparer<T> : IComparer<T>
{
    private readonly Func<T, T, Int32> comparer;

    public FunctionalComparer(Func<T, T, Int32> comparer)
    {
        this.comparer = comparer;
    }

    public Int32 Compare(T x, T y)
    {
        return comparer( x, y );
    }

    public static IComparer<T> Create(Func<T, T, Int32> comparer)
    {
        return new FunctionalComparer<T>( comparer );
    }
}

public class Idiot
{
    public Weapon[] Weapons { get; set; }
}

public class Weapon
{
    public Int32 Damage { get; set; }
}

FunctionalComparer 实现 IComparer 并根据给定的 lambda 表达式比较两个对象。 QuickSort 创建 FunctionalComparer 的实例(使用给定的表达式)并使用该实例对项目进行排序。

但是您可以使用 IEnumerable 扩展方法来执行此操作,而不是编写所有这些代码。