【问题标题】:Simplify long nested if statement workflow C#简化长嵌套 if 语句工作流 C#
【发布时间】:2016-07-05 18:56:18
【问题描述】:

此程序用于验证 Excel 行数据。 如果 if 语句为假,我需要在字符串中附加一条消息,等等 N 个 if 语句。这不起作用,因为您可以看到第一个 if 语句是否失败,我不会继续执行其他 if 语句。稍后,我需要处理 100 多列,所以我正在寻找一种方法来做到这一点。

有没有其他方法可以重写它,使其更具可读性和更少重复?我知道我可以做一个巨大的 if (.. && ....) 来验证所有单元格和单个 if 语句以附加消息,但我想知道是否有另一种方法可以做到这一点。我想保留错误的顺序,但这并不重要。结果将类似于 "facilityID is invalid, daysOfTheWeek is invalid" 我还返回一个自定义的 Pair 数据类型。

string facilityID, facilityDockDoorID, increment, hoursOfOperationId, updatedById, startTime, endTime, dockDoorServiceType, daysOfTheWeek;
            facilityID = row[0];
            facilityDockDoorID = row[1];
            increment = row[2];
            hoursOfOperationId = row[3];
            updatedById = row[4];
            startTime = row[5];
            endTime = row[6];
            dockDoorServiceType = row[7];
            daysOfTheWeek = row[8];

            string errorMessage = " is invalid";
            if (IsInt(facilityID))
            {
                if (IsInt(facilityDockDoorID))
                {
                    if (IsInt(increment))
                    {
                        if (IsInt(hoursOfOperationId))
                        {
                            if (IsInt(updatedById))
                            {
                                if (IsTime(startTime))
                                {
                                    if (IsTime(endTime))
                                    {
                                        if (IsValidDockDoorServiceType(dockDoorServiceType))
                                        {
                                            if (IsValidDayOfTheWeek(daysOfTheWeek))
                                            {
                                                isDataValid.First = true;
                                            }
                                            else
                                            {
                                                isDataValid.Second += "daysOfTheWeek" + errorMessage + ",";                                                
                                            }
                                        }
                                        else
                                        {
                                            isDataValid.Second += "dockDoorServiceType" + errorMessage + ",";

                                        }
                                    }
                                    else
                                    {
                                        isDataValid.Second += "endTime" + errorMessage + ",";
                                    }
                                }
                                else
                                {
                                    isDataValid.Second += "startTime" + errorMessage + ",";
                                }
                            }
                            else
                            {
                                isDataValid.Second += "updatedById" + errorMessage + ",";
                            }
                        }
                        else
                        {
                            isDataValid.Second += "hoursOfOperationId" + errorMessage + ",";
                        }
                    }
                    else
                    {
                        isDataValid.Second += "increment" + errorMessage + ",";
                    }
                }
                else
                {
                    isDataValid.Second += "facilityDockDoorID" + errorMessage + ",";
                }
            }
            else
            {
                isDataValid.Second = "facilityID" + errorMessage + ",";
            }
            return isDataValid;
        }

【问题讨论】:

  • 不要嵌套if 语句,按顺序执行。
  • @nicholas 我看了那个问题。但是,我不打算从任何 if 语句中返回。仅打算在通过所有检查后返回。最重要的部分是获取消息
  • 但是您发布的代码示例在第一次检查失败后会短路并返回
  • 我明白你在说什么。我认为那是我的错误。我要把return放在外面,我在复制粘贴我的代码时不小心把它放在里面

标签: c# if-statement


【解决方案1】:

如果您反转 if 语句并在每个语句中返回,您可以像这样将代码展平。

if (!IsInt(facilityID))
{
    isDataValid.Second = "facilityID" + errorMessage + ",";
    return isDataValid;
}
if (!IsInt(facilityDockDoorID))
{
    isDataValid.Second += "facilityDockDoorID" + errorMessage + ",";
    return isDataValid;
}
if (!IsInt(increment))
{
    isDataValid.Second += "increment" + errorMessage + ",";
    return isDataValid;
}
if (!IsInt(hoursOfOperationId))
{
    isDataValid.Second += "hoursOfOperationId" + errorMessage + ",";
    return isDataValid;
}
if (!IsInt(updatedById))
{
    isDataValid.Second += "updatedById" + errorMessage + ",";
    return isDataValid;
}
if (!IsTime(startTime))
{
    isDataValid.Second += "startTime" + errorMessage + ",";
    return isDataValid;
}
if (!IsTime(endTime))
{
    isDataValid.Second += "endTime" + errorMessage + ",";
    return isDataValid;
}
if (!IsValidDockDoorServiceType(dockDoorServiceType))
{
    isDataValid.Second += "dockDoorServiceType" + errorMessage + ",";
    return isDataValid;
}
if (IsValidDayOfTheWeek(daysOfTheWeek))
{
    isDataValid.First = true;
}
else
{
    isDataValid.Second += "daysOfTheWeek" + errorMessage + ",";
}
return isDataValid;

但是,基于您连接到 Second 的事实,您实际上更可能想要类似

if (!IsInt(facilityID))
    isDataValid.Second = "facilityID" + errorMessage + ",";
if (!IsInt(facilityDockDoorID))
    isDataValid.Second += "facilityDockDoorID" + errorMessage + ",";
if (!IsInt(increment))
    isDataValid.Second += "increment" + errorMessage + ",";
if (!IsInt(hoursOfOperationId))
    isDataValid.Second += "hoursOfOperationId" + errorMessage + ",";
if (!IsInt(updatedById))
    isDataValid.Second += "updatedById" + errorMessage + ",";
if (!IsTime(startTime))
    isDataValid.Second += "startTime" + errorMessage + ",";
if (!IsTime(endTime))
    isDataValid.Second += "endTime" + errorMessage + ",";
if (!IsValidDockDoorServiceType(dockDoorServiceType))
    isDataValid.Second += "dockDoorServiceType" + errorMessage + ",";
if (!IsValidDayOfTheWeek(daysOfTheWeek))
    isDataValid.Second += "daysOfTheWeek" + errorMessage + ",";
isDataValid.First = isDataValid.Second.Length == 0;
return isDataValid;

请注意,我正在比较 Second 的长度以确定是否发生任何错误。

【讨论】:

  • 我认为这是我最后的手段。我想知道我是否可以做一些类似于 switch() 的事情,但是对于顺序 if 语句。因为稍后,此方法将需要 100 多个 if 语句来处理 100 多列
  • 如果您要进行大量此类检查,您可能需要构建某种通用“方案”验证器函数,该函数循环遍历列并使用循环与预期的数据类型进行比较而不是硬编码的函数。您可以将预期的类型放在逗号分隔的列表中,例如“int, int, date, date, string”,将它们拆分,并在循环内切换。
  • @BradleyUffner,是的,我将做很多此类检查,这就是为什么我正在寻找更合适的解决方案。我会试试你的建议。同时,我将接受此作为临时解决方案,因为它确实可以完成我希望当前代码执行的操作。
【解决方案2】:

您可以反转 if 语句。例如:

if(!IsInt(facilityID))
{
    isDataValid.Second = "facilityID" + errorMessage + ",";
}
if(!IsInt(facilityDockDoorID))
{
    isDataValid.Second += "facilityDockDoorID" + errorMessage + ",";
}

【讨论】:

  • OP 还需要添加 return 语句才能获得相同的行为。
  • 这是否意味着,我需要有 8 个单独的 if 语句才能附加。然后我还需要一个巨大的 if ( ... && ... && ...) 来检查所有数据是否都经过验证?我正在返回一个自定义的 Pair 结构 btw。不仅仅是一个布尔值
  • @ygongdev 不。您可以检查您的错误消息中是否包含任何文本,或者设置其他错误标志以便稍后检查。
【解决方案3】:

您可以构建一组验证器函数,例如:

List<Func<string[], StringBuilder, bool>> validators = new List<Func<string[], StringBuilder, bool>>();

validators.Add((row, logger) => 
{
    string facilityID = row[0];

    if(IsInt(facilityID))
    {
        logger.AppendLine("facilityID is invalid");

        return false;
    }

    return true;
});

validators.Add((row, logger) =>
{
    string increment = row[2];

    if (IsInt(increment))
    {
        logger.AppendLine("increment is invalid");

        return false;
    }

    return true;
});

. . .

然后你可以像这样循环遍历所有内容:

StringBuilder log = new StringBuilder();

if(validators.Any(v => v(rows, log) == false))
{
    return false;
}
else
{
    return true;
}

isDataValid.Second = log.ToString();

通过这种方式,您可以将验证器逻辑分解成更小的块。这避免了嵌套if 语句。每个验证器负责挑选要验证的数据,返回有效/无效bool,并将任何消息记录到公共StringBuilder。随着验证器列表的增加,您只需向集合中添加一个新函数即可。

【讨论】:

  • 我喜欢这个实现,因为你可以更进一步。对于超级干净的代码,理想情况下,您需要以一种可以更改或修改的方式定义架构,只需对该代码进行最少的更新。
【解决方案4】:

最好将架构与代码功能分开。 这使您可以在将来更改架构,而无需更改其余代码。

    public class SchemaItem
    {
        public int Index;
        public string ColumnName;
        public int ParsedValue;

        public SchemaItem(int index, string columnName)
        {
            Index = index;
            ColumnName = columnName;
        }
    }
    public static Dictionary<int, SchemaItem> Schema = new Dictionary<int, SchemaItem>
    {
        {0, new SchemaItem(0, "facilityID")},
        {1, new SchemaItem(1, "facilityDockDoorID")},
        {2, new SchemaItem(2, "increment")},
        {3, new SchemaItem(3, "hoursOfOperationId")},
        {4, new SchemaItem(4, "updatedById")},
        {5, new SchemaItem(5, "startTime")},
        {6, new SchemaItem(6, "endTime")},
        {7, new SchemaItem(7, "dockDoorServiceType")},
        {8, new SchemaItem(8, "daysOfTheWeek")},
    };
    private static bool ParseIntAndOrWriteFailMessage(string[] row, StringBuilder logger, int index)
    {
        string cellContents = row[index];
        string columnName = Schema[index].ColumnName;
        int intContents = -1;
        if (int.TryParse(cellContents, out intContents))
        {
            Schema[index].ParsedValue = intContents;
            return true;
        }
        logger.AppendFormat("{0} is invalid,", columnName);
        return false;
    }

那么最后你会这样做:

        StringBuilder logger = new StringBuilder();
        foreach (var column in Schema.Select(pair => pair))
        {
            ParseIntAndOrWriteFailMessage(row, logger, column.Key);
        }
        // Parsed values are now stored in the Schema Dictionary (which probably could use a better name)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-05
    • 1970-01-01
    • 2014-07-12
    相关资源
    最近更新 更多