动态切换比较符号(小于、大于或等于)的方法是什么?

4

基本上,我为用户提供了一个选项,根据文件大小对一组文件进行过滤。

用户从下拉列表中选择一个比较类型(大于、小于、等于),然后输入一个大小(以字节为单位)进行比较。这是我目前的内容:

switch (cmboCompareType.SelectedText)
{
    case "Greater Than":
        fileOK = fi[i].Length > int.Parse(txtByteValue.Text);
        break;
    case "Less Than":
        fileOK = fi[i].Length < int.Parse(txtByteValue.Text);
        break;
    case "Equal To":
        fileOK = fi[i].Length == int.Parse(txtByteValue.Text);
        break;
}

有没有更优雅的方式在C#中进行这种比较而不需要重复那么多代码?
8个回答

20

有两种选择:

  1. 使用 CompareTo 和 Sign:
int requiredSign;
switch (cmboCompareType.SelectedText)
{
   case "Greater Than": requiredSign = 1; break;
   case "Less Than": requiredSign = -1; break;
   case "Equal To": requiredSign = 0; break;
   default: throw new ArgumentException();
}
fileOK = Math.Sign(fi[i].Length.Compare(txtByteValue.Text)) == requiredSign;
  1. 使用委托:
static readonly Func<int, int, bool> GreaterThan = (x, y) => x > y;
static readonly Func<int, int, bool> LessThan = (x, y) => x < y;
static readonly Func<int, int, bool> Equal = (x, y) => x == y;
...

Func<int, int, bool> comparison;
switch (cmboCompareType.SelectedText)
{
   case "Greater Than": comparison = GreaterThan; break;
   case "Less Than": comparison = LessThan; break;
   case "Equal To": comparison = Equal; break;
   default: throw new ArgumentException();
}
fileOK = comparison(fi[i].Length, int.Parse(txtByteValue.Text));

委托选项为代码解决了DRY问题,而不会牺牲可读性。+1 - JohnFx
+1:动态选择委托,而不是特定的值,是一种被低估的设计模式。它也比Math.Sign方法更具可扩展性:如果OP向下拉菜单添加更多项,他可以很容易地修改代码,从Dictionary<string,Func<int,int,bool>>中检索适当的比较器。 - Juliet
我也更喜欢选项2。标志选项更多是一种“哦,那也可以”的选择 :) - Jon Skeet
2
虽然我总是很喜欢John Skeet扩展思维的回答,但我认为在这种情况下,这两种解决方案都过于复杂了。这是一个艰难的选择,但我想我会接受更简单的答案。 - Neil N

10
int value = int.Parse(txtByteValue.Text);
int len = fi[i].Length;

switch (cmboCompareType.SelectedText)
{
    case "Greater Than": fileOK = len > value; break;
    case "Less Than": fileOK = len < value; break;
    case "Equal To": fileOK = len == value; break;
}

太棒了!减少了重复。 ;P


那部分很明显。我正在寻找更多“动态”比较的内容。 - Neil N
好吧,你没有要求动态比较...你只是要求减少重复。我只是想表达一下观点。;P - jrista
好的,题目确实说“如何动态切换...”,虽然我不得不承认,这个答案是最简单、可能也是迄今为止最“优雅”的答案。 - Neil N
1
你让我笑了,先生。 :D +1 为最后的“TADA!” - JustLoren
1
由于我猜测在C#中我所寻找的“动态”水平并不是真正可能的,因此我更喜欢这个语言,因为它更加清晰简洁。 - Neil N
显示剩余3条评论

5

我不是case语句的粉丝,但这只是另一种方式。


var fileOK = new Dictionary<string, Func<int, int, bool>>
    (StringComparer.OrdinalIgnoreCase)
    {
        { "Greater Than", (x, y) => x > y },
        { "Less Than", (x, y) => x < y },
        { "Equal To", (x, y) => x == y }
    }[cmboCompareType.SelectedText](fi.Length, int.Parse(txtByteValue.Text));

1
int actual = Math.Sign(fi[i].Length.CompareTo(int.Parse(txtByteValue.Text)));
int expected;

switch (cmboCompareType.SelectedText)
{
    case "Greater Than": expected = +1; break;
    case "Less Than":    expected = -1; break;
    case "Equal To":     expected =  0; break;
}

fileOK = (actual == expected);

1
如果你有一个地图,你可以使用类似以下的代码:
private int CompareOp(string Text)
{
    switch (cmboCompareType.SelectedText)
    {
        case "Greater Than": 
            return 1;
        case "Less Than": 
            return -1;
        case "Equal To": 
            return 0;
    }
}

// In your method:
fileOK = (fi[i].Length.CompareTo(value) == CompareOp(cmboCompareType.SelectedText);

1
在 int 上创建一个扩展方法。
public static int Compare(this int a, int b, string compareType)
{
    switch (CompareType)
    {
        case "Greater Than":
            return fi[i].Length > int.Parse(txtByteValue.Text);
            break;
        case "Less Than":
            return fi[i].Length < int.Parse(txtByteValue.Text);
            break;
        case "Equal To":
            return fi[i].Length == int.Parse(txtByteValue.Text);
            break;
    }
}

然后将其用作:

fileOK = fi[i].Length.Compare(int.Parse(txtByteValue.Text), cmboCompareType.SelectedTex);

不解决“不要重复自己”的问题。 - Nathan Koop
@Nathan:这取决于使用频率。如果在许多不同的地方进行此比较,则扩展方法将显示在每个int上,因此只需实现一次Compare方法并在所有地方使用即可。 - Jeff Hornby

1

您还可以将值-1、0、1添加到每个组合框项的值属性中,然后代码将如下所示:

fileOK = fi[i].Length.CompareTo(int.Parse(txtByteValue.Text) == cmboCompareType.SelectedValue;

是的,这就是我的思考过程,让我得出了刚刚添加的答案。但是我没有添加值,而是将索引偏移了一个。 - Neil N

0

这是我的想法,受到使用 Math.Sign() 的解决方案的启发。由于下拉框有三个值,它们将具有索引 0、1 和 2,我可以减去 1 得到 -1、0、1,然后将其与符号进行比较,如下所示:

int sign = Math.Sign(fi[i].Length.CompareTo(int.Parse(txtByteValue.Text)));
fileOK = sign == (cmboCompareType.SelectedIndex - 1);

这将取决于列表框中的项目按照以下特定顺序排列:
小于
等于
大于

当然,只有这些值会出现在列表框中才能正常工作。这可能不是最好的解决方案,但我很高兴我只用了两行代码就完成了它。

编辑:技术上我可以将其简化为一行代码:

fileOk=(cmboCompareType.SelectedIndex-1) == Math.Sign(fi[i].Length.CompareTo(int.Parse(txtByteValue.Text)));

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