【问题标题】:c# - Cannot convert lambda expression to delegate type; but this works in List functionsc# - 无法将 lambda 表达式转换为委托类型;但这适用于列表函数
【发布时间】:2015-05-14 16:24:36
【问题描述】:

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

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

抛出“无法将 lambda 表达式转换为委托类型”异常,而在 List 类的函数中发生完全相同的事情,即

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 委托,这与我正在做的完全一样。

【问题讨论】:

  • 我怀疑p =&gt; p.Damage 返回bool,你的谓词肯定是Func&lt;T, bool&gt;,而不是Func&lt;T, int&gt;或什么的。
  • 你能发布更多你的代码吗?
  • 您是在运行时遇到异常还是编译错误?请添加完整的错误消息。
  • 发布错误消息是个好主意 - 错误 1 ​​无法在此范围内声明名为“i”的局部变量,因为它会给已使用的“i”赋予不同的含义在“父或当前”范围内表示其他内容。此错误消息是完全自我描述的,与类型推断无关。如果你重命名 lambda 中的第一个 i 或 i ,一切都会正常编译。

标签: c# function methods delegates


【解决方案1】:

这行得通:

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

编辑:

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

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

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

如果您使用 List 的 Sort(int index, int count, IComparer comparer) 方法,则需要一个 IComparer 实例来比较列表项。如果您希望能够将比较器指定为 lambda 表达式,则需要一个实现 IComparer 的类,该类在内部使用 lambda 表达式来比较项目。 (或者使用 .net 4.5 你可以使用Comparer&lt;T&gt;.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 扩展方法来执行此操作,而不是编写所有这些代码。

【讨论】:

    猜你喜欢
    • 2016-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多