我可以将一个嵌套的lambda表达式存储在Dictionary中吗?

本文关键字:存储 表达式 lambda Dictionary 中吗 嵌套 一个 我可以 | 更新日期: 2023-09-27 18:14:14

我想在c#中将字符串解析为lambda表达式,例如,将"lt 5"解析为x => x < 5,以便我可以将其用作Enumerable.Where的参数:

static void Main(string[] args)
{
    Enumerable
        .Range(0,10)
        .Select(x => (double)x)
        .Where(Parse("lt 5"))
        .ToList()
        .ForEach(System.Console.WriteLine);
}
private const List<Tuple<List<string>, Func<double, Func<double, bool>>>> operationList =
    new Dictionary<string, Func<double, Func<double, bool>>>()
    { { "lt <",     val => ( x => x <  val ) }
    , { "le <=",    val => ( x => x <= val ) }
    , { "eq = ==" , val => ( x => x == val ) }
    , { "ne != <>", val => ( x => x != val ) }
    , { "ge >=",    val => ( x => x >= val ) }
    , { "gt >",     val => ( x => x >  val ) } }
    .Select(kv =>
        new Tuple<
            List<string>,
            Func<double, Func<double, bool>>>(
                kv.Key.Split(' ').ToList(),
                kv.Value))
    .ToList();
public static Func<double, bool> Parse(string raw)
{
    var fields = raw.Split(' ');
    var predKey = fields[0].ToLower();
    var predBuilder = operationList.FirstOrDefault(tp =>
        tp.Item1.FirstOrDefault(key => key.Equals(predKey)) != null);
    return predBuilder.Item2(double.Parse(fields[1]));
}

首先,我做了一个operationList,它存储一个元组,其中Item1描述了操作符的所有别名,Item2存储了操作符的curry版本。

Parse将字符串lt 5拆分为["lt","5"],并根据关键字lt搜索操作。

最后,如果我能找到操作,5将部分应用于它,结果将是一个lambda表达式x => x < val

然而,编译器对{ "lt <", val => ( x => x < val ) }很生气,并抱怨"表达式不能包含匿名方法或lambda表达式"。

我不知道这是什么意思,也不知道如何让事情工作。

我可以将一个嵌套的lambda表达式存储在Dictionary中吗?

const改为readonly,改为static,如下所示:

private readonly static List<Tuple<List<string>, Func<double, Func<double, bool>>>> operationList =
    new Dictionary<string, Func<double, Func<double, bool>>>()
    { { "lt <",     val => ( x => x <  val ) }
    , { "le <=",    val => ( x => x <= val ) }
    , { "eq = ==" , val => ( x => x == val ) }
    , { "ne != <>", val => ( x => x != val ) }
    , { "ge >=",    val => ( x => x >= val ) }
    , { "gt >",     val => ( x => x >  val ) } }
    .Select(kv =>
        new Tuple<
            List<string>,
            Func<double, Func<double, bool>>>(
                kv.Key.Split(' ').ToList(),
                kv.Value))
    .ToList();

在c#中,const关键字用于表示编译时间常量,但在您的示例中,列表是在运行时使用LINQ计算的。

在c#中const的值总是静态的,将其设置为只读会将字段的作用域更改为instance。

注意,列表的内容可能在执行过程中发生变化,readonly不会阻止您删除和添加元组到列表中。考虑使用ReadOnlyCollection(它仍然不会阻止你修改它,只是会使它更难)或使用不可变集合(它不是.net BCL的一部分)