0

我想将一个字符串解析为 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存储了运算符的柯里化版本。

然后Parse将字符串拆分lt 5["lt","5"]根据 key 进行搜索操作lt

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

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

我不知道这意味着什么以及如何让事情发挥作用。

4

1 回答 1

1

更改constreadonly并制作它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中,值始终是静态的,将其设为只读会将字段的范围更改为实例。

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

于 2013-05-19T10:07:31.727 回答