简体   繁体   English

简化长嵌套的if语句工作流C#

[英]Simplify long nested if statement workflow C#

This program is for validating Excel row data. 该程序用于验证Excel行数据。 If a if statement is false, I need to append a message to a string and so forth for N number of if statements. 如果if语句为假,则需要将消息附加到字符串,依此类推,以获取N个if语句。 This doesn't work because as you can see if the first if statement fails, I would not proceed onto the the other if statements. 这是行不通的,因为如您所见,如果第一个if语句失败,那么我不会继续处理其他if语句。 Also later on, I'll need to handle 100+ columns, so I'm looking for a way to do this. 同样,稍后,我将需要处理100多个列,因此我正在寻找一种实现此目的的方法。

Is there any other way I can rewrite this, so it is more readable and less repetitive? 我还有其他方法可以重写此代码,从而使其更具可读性和重复性吗? I know I can just do a giant if (.... && ....) for validating all cells and individual if statements to append messages, but I was wondering if there is a another way to do this. 我知道我可以做一个巨大的if(.... && ....)来验证所有单元格和单个if语句以追加消息,但是我想知道是否还有另一种方法可以做到这一点。 I would like to preserve the order of the errors, but that is not as important. 我想保留错误的顺序,但这并不重要。 The result would be something like "facilityID is invalid, daysOfTheWeek is invalid" I'm also returning a custom Pair datatype. 结果将类似于"facilityID is invalid, daysOfTheWeek is invalid"类的东西"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 you invert the if statements and return inside each one you can flatten your code out like this. 如果反转if语句并在每个语句中返回, 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;

However based on the fact that you are concatenating to Second it's more likely that you actually want something like 但是基于您连接到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;

Notice that I'm comparing the length of Second to determine if any errors occurred. 请注意,我正在比较Second的长度,以确定是否发生任何错误。

You could invert the if statements. 您可以反转if语句。 For instance: 例如:

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

You could build a collection of validator functions, for example: 您可以构建验证器函数的集合,例如:

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;
});

. . .

You can then just loop through all like so: 然后,您可以像这样循环遍历所有内容:

StringBuilder log = new StringBuilder();

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

isDataValid.Second = log.ToString();

This way you can break the validator logic up until into smaller chunks. 这样,您可以将验证器逻辑分解为更小的块。 This avoid nesting the if statements. 这样可以避免嵌套if语句。 Each validator is responsible for picking the data it wants to validate, returning a valid/invalid bool , and logging any messages to the common StringBuilder . 每个验证器负责选择要验证的数据,返回有效/无效bool ,并将所有消息记录到公共StringBuilder As your list of validators grows you can just add a new function to the collection. 随着验证者列表的增加,您可以仅向集合添加新功能。

It's best to break your schema apart from your code functionality. 最好将模式与代码功能分开。 This allows you to change the schema in the future without having to change the rest of the code. 这使您将来可以更改架构,而不必更改其余代码。

    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;
    }

Then finally you would do: 然后,最后您会这样做:

        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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM