【问题标题】:Is it possible to optimize these if-else statements? [closed]是否可以优化这些 if-else 语句? [关闭]
【发布时间】:2021-10-11 02:26:31
【问题描述】:

我是 C# 新手,想知道这段代码是否有更好的结构:


此代码根据捷克出生号码 = 捷克共和国的个人身份证号码确定真实月份。那里的数字是不变的。

private ushort RawMonth
// get raw integer month code without resolving it
{
    get { return Convert.ToUInt16(SanitizedBirthNumberString.Substring(2, 2)); }
}


if (RawMonth >= 01 && RawMonth <= 12)
{
    return RawMonth;
}
else if (RawMonth >= 51 && RawMonth <= 62)
{
    return RawMonth - 50;
}
else if (RawMonth >= 21 && RawMonth <= 32)
{
    return RawMonth - 20;
}
else if (RawMonth >= 71 && RawMonth <= 82)
{
    return RawMonth - 70;
}
else
{
    // just some of my custom exceptions
    throw new MonthCodeInvalidException();
}

只有我一个人吗?因为那些 if-else 语句看起来已被弃用。谢谢。


我不得不进行一些重大调整,首先将 C# 语言版本设置为 9.0。

但最终,我有这段代码,它可以编译,我只是从未使用过这样的语法,请检查我,谢谢。

public ushort ResolvedMonth
{
    get => RawMonth switch
    {
         >= 01 and <= 12 => RawMonth,
         >= 21 and <= 32 => (ushort)(RawMonth - 20),
         >= 51 and <= 62 => (ushort)(RawMonth - 50),
         >= 71 and <= 82 => (ushort)(RawMonth - 70),
         _ => throw new MonthCodeInvalidException()
    };
}

有趣的是,为了运行它,我不得不使用 typecast,不知道为什么......但无论如何 - 看起来更整洁。

注意:它使用C# 9.0 introduced Relational patterns(链接到 MS C# 参考)。

【问题讨论】:

  • 这里奇怪的不是 if 语句。 rawMonth 是什么意思?为什么它可以大于 12?如果您解释这应该做什么,也许有更好的解决方案。
  • 将所有这些三元组 (1,12,0), (51,62,50) ... 放入辅助表中并在表上方做一个 for
  • 我投票结束这个问题,因为它要求改进工作代码 - 请在Code Review
  • 捷克的出生号码是多少?问题的完整陈述可能会有所帮助。但如果那里没有模式 - 只需使用 if-else,无需过于复杂。
  • 这不是我们需要的解释。我的意思是“它的第 3 位和第 4 位数字代表一个月,这就是我的示例中的 RawMonth。对于女性,50 被添加到月份数中,对于男性来说,它只是简单的月份数”。跨度>

标签: c# if-statement optimization


【解决方案1】:

如果您希望它们被硬编码,并且您的输入通常不会有错误的值,您可以按递增顺序进行模式匹配:

RawMonth switch
{
  <=12 => RawMonth,
  <=32 => RawMonth-20,
  <=62 => RawMonth-50,
  <=82 => RawMonth-70,
  _ => throw ...
}

如果您输入错误并需要范围:

RawMonth switch
{
  (>=1) and (<=12) => RawMonth,
  (>=21) and (<=32) => RawMonth-20,
  (>=51) and (<=62) => RawMonth-50,
  (>=71) and (<=82) => RawMonth-70
    _ => throw ...
}

括号是可选的;我发现它有助于提高可读性,但您的意见可能会有所不同!

遗憾的是数字模式不是更一致(例如,如果 20 范围实际上从 30 开始),因为您可以将它们修改为 20,但我想您可以减少 10 或 20,直到它们进入范围

if(RawMonth>40)
  RawMonth -= 10;

while(RawMonth>12)
  RawMonth -= 20;

if(RawMonth < 1)
  throw ...

return RawMonth;

我认为这就是逻辑(虽然我没有输入任何 >82 签入)

【讨论】:

  • dotnetfiddle.net/NBgmyf - 为缩进道歉;在手机上,编辑并没有真正玩过它
  • 你成就了我的一天,这就是我认为的整洁。再次感谢,先生。
  • 如果您问为什么必须进行强制转换,那是因为您从 RawMonth 中减去了一些整数。我想 RawMonth 是一个 ushort;因为您已经从中减去了例如 int 70,所以它使结果为 int。除了在其他地方放置例如 `ushort SEVENTY = 70; 之外,没有办法将 70 指定为 ushort;并改用变量。将 RawMonth 和 ResolvedMonth 设置为 int 可能更容易
  • 如果你不想让它变得有趣,你就无法摆脱演员阵容,但你可以只做一个;将整个 RawMonth switch{...} 转换为 ushort 例如 get =&gt; (ushort)(RawMonth switch...);
【解决方案2】:

原则上if .. else if .. else 没有问题(对于像你这样的少数情况)。但是您也可以创建一个包含上下限和相应递减值的元组列表,然后在该列表中搜索正确的元组。

//create a list with lower and upper limits and the respective decrement value
var limits = new List<(int, int, int)> {
    (1, 12, 0),  //lower limit, upper limit, decrement value
    (21, 32, 20),
    (51, 62, 50),
    (71, 82, 70)
};
    
var rawmonth = 23;
//find the respective interval for your given rawmonth
var d = limits.FirstOrDefault(x => x.Item1 <= rawmonth && x.Item2 >= rawmonth);

//if nothing is found, d will be (0,0,0)
if (d.Item1 == 0)
  throw new YourCustomException();

//substract the respective decrementvalue
rawmonth -= d.Item3;

【讨论】:

  • 如果您在List&lt;(int,int,int)&gt; 中添加标签,则可以使用它们代替 Item1/2
【解决方案3】:

如果整数有意义,我建议命名整数,不要有其他人难以阅读和理解的幻数

当我发现自己有类似的情况时,我将条件放在字典中的委托中,并在方法中尝试通过键获取匹配并从字典中返回值,如果不存在则返回默认值

我附上了一个链接来证明我的观点Avoid If Statements

【讨论】:

    【解决方案4】:

    使用前面提到的 herehere 的 switch 语句。

    第一个链接的样式:

    switch (RawMonth)
    {
        case int n when n >= 01 && n <= 12:
            ...
            break;
        case int n when n >= 51 && n <= 62:
            ...
            break;
        ...
    }
    

    【讨论】:

    • 这是一个奇怪的结构,不是吗?它比将 RawMonth 别名为 n 并使用 if else ..
    【解决方案5】:

    if-else 语句首先是不折旧的。你可以保持原样。您还可以使用带有表达式的 switch 语句。

        int output = RawMonth switch
                {
                    int Month when Month >= 01 && Month <= 12 => Month,
                    int Month when Month >= 51 && Month <= 62 => Month - 50,
                    int Month when Month >= 71 && Month <= 82 => Month - 70,
                    _ => throw new Exception("th")
                };
    return output ;
    

    上面的代码甚至可以简化为

            int output = RawMonth switch
            {
                >= 01 and <= 12 => RawMonth,
                >= 51 and  <= 62 => RawMonth - 50,
                >= 71 and  <= 82 => RawMonth - 70,
                _ => throw new Exception("th")
            };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-23
      • 2011-05-18
      • 1970-01-01
      • 2015-06-09
      • 2023-03-28
      • 1970-01-01
      • 2017-09-05
      • 2017-10-16
      相关资源
      最近更新 更多