有没有一种方法可以在C#中对运算符进行参数化?

4
假设我有两个处理程序increment_click和decrement_click,它们调用共同的方法。
实际上,我的方法可能更加复杂,我想避免使用if之类的语法。
if (operator == "+") {
     return value = value + step
}
else {
     return value = value - step
}

并且做一些更通用的事情,像这样

increment(value, operator, step) {
     return value = value <operator> step
}

有什么办法可以实现吗?

你可以使用枚举来实现。http://msdn.microsoft.com/zh-cn/library/sbbt4032.aspx - Orel Eraki
一个 enum 仍需要在其后使用 switchif - Niels Keurentjes
在调用方,"operator" 值是否在编译时已知? - Ani
第一种语法有什么问题? - Zaheer Ahmed
@NielsKeurentjes,当然可以,但这只会是一个用于永久使用的函数处理它。 - Orel Eraki
显示剩余3条评论
4个回答

11
你可以创建一个 Dictionary<string,Func<decimal,decimal,decimal>>,并用你的运算符实现来设置它,像这样:
private static readonly IDictionary<string,Func<decimal,decimal,decimal>> ops = new Dictionary<string,Func<decimal,decimal,decimal>> {
    {"+", (a,b) => a + b}
,   {"-", (a,b) => a - b}
,   {"*", (a,b) => a * b}
,   {"/", (a,b) => a / b}
};

现在你可以这样做:
decimal Calculate(string op, decimal a, decimal b) {
    return ops[op](a, b);
}

您甚至可以通过使用 Linq.Expressions 中的一些“魔法”来通用地进行此操作:不使用在 C# 中定义的预构建 Lambda,而是以编程方式定义 Lambda,并将其编译为 Func<T,T,T>


2
虽然我喜欢这个解决方案,但它并不是真正回答实际问题的答案——你仍然在运行时解析,因此本质上这只是一个重写的 switch 语句。不过创意值得赞扬,+1 :) - Niels Keurentjes
虽然有些繁琐,但这确实回答了我的问题 :) - user310291

2

我认为这并不比较好,但这是一个不错的选项。

int sign = (operator == "+" ? 1 : -1);
retrun value +sign*value;

1
呵呵,“??”的笔误导致了这个后续问题:http://stackoverflow.com/questions/17014079/how-to-use-c-sharp-for-this-expression 我会在这个答案中进行更正。 - Anders Forsgren

2

我不确定你的整个使用情况,但似乎适合使用委托的场景。让我们先定义一个委托:

public delegate T Operation<T>(T arg, T step);

现在假设您有一个带有运算符的类:

public class Foo
{
    public static Foo operator + (Foo left, Foo right) { ... } 
    public static Foo operator + (Foo left, Foo right) { ... } 
}

如果您想通用地处理逻辑,则可以使用类似的代码:

public class Bar
{
    // The method you look for:
    public Foo Increment(Foo value, string @operator, Foo step)
    {
         Operation<Foo> operation = null;

         switch(@operator)
         {
             case "+":
                 operation = (v, s) => v + s;
                 break;
             case "-":
                 operation = (v, s) => v - s;
                 break;
             ...
         }

         if (operation != null)
         {
             return operation(value, step);
         }
         else
         {
             throw new NotSupportedException(
                 "Operator '" +  @operator "' is not supported");
         }
    }
}

为了更好的阐述,我使用了Foo类,但实际上你可以使用.NET中支持这些操作的任何原始类型(如intdoublelong等)。

不必自己定义委托(例如Operation<T>),可以使用内置的Func<T, T>

我建议您使用枚举而不是字符串来表示运算符(如+-等),因为字符串可能会传递无效值。


1
不,你只能将变量进行参数化,并将类型泛型化。

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