C#: 有没有一种方法可以将表达式用作变量/参数?

5

我想知道在C#中是否可以将表达式用作变量/参数。我想要做类似这样的事情:

int x = 0;
public void g()
{
   bool greaterThan = f("x>2");
   bool lessThan = f("x<2");
}
public bool f(Expression expression)
{
   if(expression)
       return true;
   else
       return false;
}

以下是我不想做的事情:

int x = 0;
public void g()
{
    bool greaterThan = f(x, '<', 2);
}

public bool f(int x, char c, int y)
{
    if(c == '<')
       return x < y;
    if(c == '>')
       return x > y;
}

我想说的是,有没有一种方法可以避免使用开关或一系列if语句来处理以下每个条件:< > <= >= == !=。是否有一种方法可以做到这一点?

编辑:假设表达式是一个字符串,例如“x < 2”。是否有一种方法可以在不使用一系列if语句的情况下从字符串转换为谓词?

5个回答

11

很有可能,只是语法不完全一样。

int x = 0;
public void g()
{
   bool greaterThan = f(i => i > 2, x);
   bool lessThan = f(i => i < 2, x);
}
public bool f(Func<int,bool> expression, int value)
{
   return expression(value);
}

实际上,这应该更接近您想要的。

int x = 0;
public void g()
{
   bool greaterThan = f(() => x > 2);
   bool lessThan = f(() => x < 2);
}
public bool f(Func<bool> expression)
{
   return expression();
}

回复编辑:

如果你想说f("x < 2"),几乎是不可能的。忽略解析它(这可能会变得很棘手),你必须捕获x的值,但对于f来说它只是一个字符,这使得它几乎不可能。


很好。我稍微修改了我的问题,如下所示:假设表达式是一个字符串,比如“x < 2”。有没有一种方法可以从字符串转换为谓词,而不使用一系列基于字符的if语句? - David Hodgson
1
如果它确实是一个字符串,那么没有简单快速的答案。但如果你的意思是想要输入 f(x > 2);,那么只需使 f 接受一个布尔参数即可。 - Samuel
真糟糕,好吧。谢谢你的回复。 - David Hodgson
你绝对不想自己编写解析器,但是你可以使用Dynamic LINQ库中的解析器。请查看我的回答。 - Tom Lokhorst

9

如果您真的想在此传递代码,您需要一个Predicate:

int x = 0;
public void g()
{
   bool greaterThan = f(i => i>2, x);
   bool lessThan = f(i => i<2, x);
}
public bool f(Predicate<int> expression, int value)
{
   return expression(value);
}

否则,如果你只是在第一个例子中用bool替换Expression,那么你的代码将编译得很好:
int x = 0;
public void g()
{
   bool greaterThan = f(x>2);
   bool lessThan = f(x<2);
}
public bool f(bool expression)
{
   if(expression)
       return true;
   else
       return false;
}

哇,那个踩票完全没有必要。这个答案是正确的,并且更符合提问者在语法方面想要的东西。 - Samuel
我曾经有一个占位符,只是第一句话,花了我太长时间才完善它。 - Joel Coehoorn
嗯... 应该有一个简单的 Predicate 委托(没有 <T> 部分)。为了避免需要另一个参数,使用 Func<bool> 感觉很丑陋。 - Joel Coehoorn
没有理由你不能创建自己的 Predicate。public delegate bool Predicate(); - Samuel
1
抱歉,我稍微修改了一下问题:是否有一种方法可以在不使用if语句的情况下从字符串转换为谓词?例如:string s =“x>2”;string t =“x<2”;bool b = f(s);? - David Hodgson
显示剩余3条评论

7
除非我漏掉了什么……为什么你不直接这样做:
bool greaterThan = x > 5;
bool lessThan = x < 5;

布尔比较本身就是一个表达式...

编辑:

所以,对于您的函数,只需要传递一个bool值:

public void f(bool expression) 
{
    // expression is either true or false...
}

f(x<5); // called like this

你的答案和这个帖子中其他答案的主要区别在于比较的执行时间。你的代码立即运行,而其他代码只有在调用expression时才会运行。如果你不总是需要知道greaterThanx计算起来很耗费资源,这种方式会很有用。 - Tom Lokhorst
假设 x 是一个函数调用或另一个“延迟”的表达式。 - Tom Lokhorst
谢谢您的澄清,我没有使用过.NET 3.0,所以对于Lambda表达式不太熟悉。 - John Rasch

2
编辑:假设表达式是一个字符串,比如“x < 2”。有没有一种方法可以在不使用一系列if语句的情况下从字符串转换为谓词?
正如一些人已经提到的,如果你想使用字符串,你需要解析。你不想编写自己的C#解析器,幸运的是,微软的一些人已经用Dynamic LINQ做到了这一点。
以下是针对您特定问题的解决方案:
public void g()
{
    int x = 0;

    bool greaterThan = f("x > 2", x);
    bool lessThan = f("x < 2", x);
}

public bool f(string expression, int x)
{
    ParameterExpression xExpr = Expression.Parameter(typeof(int), "x");

    LambdaExpression e = DynamicExpression.ParseLambda(
        new ParameterExpression[] { xExpr }, typeof(bool), expression);

    return (bool)e.Compile().DynamicInvoke(x);
}

显然,如果字符串中有最小的拼写错误,这将导致失败。你真的需要考虑一下是否实际需要这个功能。但如果确实需要,你可以使用DynamicExpression.ParseLambda方法将字符串解析为LambdaExpression

我其实并不是非常需要,但那很酷。我会试一试。 - David Hodgson

0
编辑:假设表达式是一个字符串,比如“x < 2”。有没有一种方法可以在不使用一系列if语句的情况下将字符串转换为谓词?
有几个技巧可以用来将字符串转换为.Net中的代码:CodeDom、Reflection.Emit,甚至是在shell中编写编译器脚本。然而,这些都不像脚本语言中快速的eval()那样简单,并且在.Net中通常被反对,除非你真的知道你在做什么。
相反,.Net提供了System.Addin命名空间作为一种更安全的方式,允许用户扩展您的应用程序。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接