0

我有一个基于枚举的方法,并且在开始时要清楚我们有这种情况:

public void MyMetohd(Somestatus status)
{
if(status == Somestatus.Enum1)
{
DoA();
DoB();
DoC();
DoD();
DoE();
}
if(status == Somestatus.Enum2)
{
DoA();
DoB();
DoC();
DoD();
}

if(status == Somestatus.Enum3)
{
DoA();
DoB();
DoC();
}

if(status == Somestatus.Enum4)
{
DoA();
DoB();
}

if(status == Somestatus.Enum5)
{
DoA();
}
}

你将如何优化这种代码(它不是我的)?

4

10 回答 10

5

如果您设置 的每个成员的值,则可以使用比较enum

enum Somestatus : int
{
    Enum1 = 1,
    Enum2 = 2,
    ...
}

然后只需使用比较来完成您的代码。因为你总是这样做DoA(),从那开始。

if(status <= Somestatus.Enum5)
    DoA();

if(status <= Somestatus.Enum4)
    DoB();

if(status <= Somestatus.Enum4)
    DoC();
...

继续这样下去。这样,当值为Enum1.

于 2011-01-02T17:28:29.857 回答
5

通过优化,我假设您的意思是“制作 DRYer”。

您将不得不在易于阅读的代码(尽管有些重复)和尽可能少重复的代码之间取得平衡

只是输入这个让我觉得很脏,但如果你想要的是 DRY 和更少的 LOC,我认为它会做你想要的。

switch (status)
            {
                case Somestatus.Enum1:
                    DoE();
                    goto SomeStatus.Enum2;
                case Somestatus.Enum2:
                    DoD();
                    goto SomeStatus.Enum3;
                case Somestatus.Enum3:
                    DoC();
                    goto SomeStatus.Enum4;
                case Somestatus.Enum4:
                    DoB();
                    goto SomeStatus.Enum5;
                case Somestatus.Enum5:
                    DoA();
                    break;
                default:
                    throw new InvalidArgumentException("Unknown Status");
            }
于 2011-01-02T17:45:01.900 回答
3

您可以在枚举值上使用字典键并使用Actionor列表Action<T>来执行。

Dictionary<int,IList<Action>> actionsPerEnumValue;

使用枚举值和每个操作填充此字典。

在您的函数中获取每个值的函数列表并调用每个操作。

foreach(var act in actionsPerEnumValue[status])
{
    act();
}

有关示例,请参见此 SO 答案

于 2011-01-02T17:25:35.523 回答
0

当您在相同的条件和不同的值下工作时,最好使用 switch..case... 当您想测试多个条件时使用 If..else。

于 2011-01-02T17:23:03.787 回答
0

如果这样做更简单,您还可以“反转”逻辑(取决于要覆盖的枚举数量与不同操作的数量):

if(status == Somestatus.Enum1 || status == Somestatus.Enum2)
 DoA();

if(status == Somestatus.Enum1 || status == Somestatus.Enum4)
 DoB();

...
于 2011-01-02T17:24:59.850 回答
0

听起来你应该使用状态模式

于 2011-01-02T17:26:29.010 回答
0

乍一看,switch语句似乎是最好的方法,但即使在其中你也有很多重复的代码:

switch (status)
{
    case Somestatus.Enum1:
        DoA();
        DoB();
        DoC();
        DoD();
        DoE();
        break;
    case Somestatus.Enum2:
        DoA();
        DoB();
        DoC();
        DoD();
        break;
    ...
}

DoA虽然这更好,但仍然不理想,因为您重复调用etc。

于 2011-01-02T17:20:18.800 回答
0

像其他人建议的那样,使用模式来解决这个问题将是最好的解决方案。我想提供另一种解决方案。

我强烈建议不要这样做。

public void MyMetohd(Somestatus status)
    DoA();
    if (status != SomeStatus.Enum5) {
        DoB();
        if (status != SomeStatus.Enum4) {
            DoC();
            if (status != SomeStatus.Enum3) {
                DoD();
                if (status != SomeStatus.Enum2) {
                    DoE();
                }
            }
        }
    }
}
于 2011-01-02T18:53:30.493 回答
0

编辑:

// ANOTHER WAY
public void MyMetohd(Somestatus status)
{
    switch(status)
    {
        case Somestatus.Enum1:
             do_("ABCDE");
             break;
        case Somestatus.Enum2:
             do_("ABCD");
             // and so on...
        }
}

public static void do_(string s)
{
    foreach(char ch in s)
    {
        switch(ch)
        {
            case 'A':
                 doA();
                 break;
            case 'B':
                 doB();
                 break;
            case 'C':
                 doC();
                 break;
            case 'D':
                 doD();
                 break;
            case 'E':
                 doE();
                 break               
        }
    }
}
于 2011-01-02T17:41:28.483 回答
0

虽然我自己会选择 Brook 的解决方案,但我想指出另一个优雅而简短的解决方案。

public void MyMethod(Somestatus status)
{
    foreach (Action toDo in new Action[] { DoA, DoB, DoC, DoD, DoE }.Take(5 - (int)status))
        toDo();
}

但是,这假设 Somestatus 定义如下:

enum Somestatus
{
    Enum1,
    Enum2,
    Enum3,
    Enum4,
    Enum5
}

作为一个学者,我喜欢这个解决方案,因为它很短,但它肯定没有很好的可读性或可维护性。

于 2011-01-02T19:30:00.527 回答