2

到目前为止,我有以下程序:

using System;
namespace ParkingTicket
{
    class Program
    {
        static void Main()
        {
            int speed;
            int yrInSchool;
            double fine;
            char choice = ' ';
            do
            {
                Console.Clear();
                speed = GetSpeed();
                if (speed <= 15)
                    Console.WriteLine("No speeding fine to pay.");
                else
                {
                    yrInSchool = GetYrInSchool();
                    fine = CalculateFine(speed, yrInSchool);
                    DisplayFine(fine);
                }
                choice = GetUserChoice();
            } while (choice != 'Q' && choice != 'q');
        }
        static int GetSpeed()
        {
            int speed;
            string userInput;
            try
            {
                Console.Write("Please enter the speed you were traveling: ");
                userInput = Console.ReadLine();
                speed = Convert.ToInt32(userInput);
            }
            catch
            {
                Console.WriteLine("\a\n INVALID - PLEASE TRY AGAIN");
                Console.Write("Please press enter to continue....");
                userInput = Console.ReadLine();
                speed = GetSpeed();  // this is the recursion - calling myself

            }
            return speed;

            // code this method
        }
        static int GetYrInSchool()
        {
            string userEntry;
            int year;

            /*************************************************************
             *  modify this method to validate the year using a Try/Catch
             *************************************************************/
            Console.WriteLine("\nClassifications");
            Console.WriteLine("\tFreshman  (enter 1)");
            Console.WriteLine("\tSophomore (enter 2)");
            Console.WriteLine("\tJunior    (enter 3)");
            Console.WriteLine("\tSenior    (enter 4)");

            try
            {
                Console.Write("Enter choice: ");
                userEntry = Console.ReadLine();
                year = Convert.ToInt32(userEntry);
            }

            catch
            {
                Console.WriteLine("\a\n INVALID - PLEASE TRY AGAIN");
                Console.Write("Please press enter to continue....");
                userEntry = Console.ReadLine();
                year = GetYrInSchool();  // this is the recursion - calling myself
            }
            return year;
        }
        static double CalculateFine(int speed, int year)
        {
            const double COST_PER_5_OVER = 87.50;
            const int SPEED_LIMIT = 15;
            const double INITIAL_FEE = 75.00;
            double fine = 0;

            if (((year == 1) && (speed >= 15) || (speed <= 19)))
            {
                fine = INITIAL_FEE - 50.00;
            }
            else if (((year == 1) && (speed >= 20) || (speed >= 24)))
            {
                fine += (INITIAL_FEE - 50.00) + COST_PER_5_OVER;
            }
            else if (((year == 1) && (speed >= 25) || (speed <= 29)))
            {
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 2);
            }
            else if (((year == 1) && (speed >= 30) || (speed <= 34)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 3);
            else if (((year == 1) && (speed >= 35) || (speed <= 39)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 4);
            else if (((year == 1) && (speed >= 40) || (speed <= 44)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 5);
            else if (((year == 1) && (speed >= 45) || (speed <= 49)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 6);
            if (((year == 1) && (speed >= 50) || (speed <= 54)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 7);
            if (((year == 1) && (speed >= 55) || (speed <= 59)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 8);
            if (((year == 1) && (speed >= 60) || (speed <= 64)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 9);
            if (((year == 1) && (speed >= 65) || (speed <= 69)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 10);
            if (((year == 1) && (speed >= 70) || (speed <= 74)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 11);
            if (((year == 1) && (speed >= 75) || (speed <= 79)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 12);
            if (((year == 1) && (speed >= 80) || (speed <= 84)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 13);
            if (((year == 1) && (speed >= 85) || (speed <= 89)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 14);
            if (((year == 1) && (speed >= 90) || (speed <= 94)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 15);
            if (((year == 1) && (speed >= 95) || (speed <= 99)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 16);
            if (((year == 1) && (speed >= 100) || (speed <= 104)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 17);
            if (((year == 1) && (speed >= 105) || (speed <= 109)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 18);
            if (((year == 1) && (speed >= 110) || (speed <= 114)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 19);
            if (((year == 1) && (speed >= 115) || (speed <= 119)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 20);
            if (((year == 1) && (speed >= 120) || (speed <= 124)))
                fine = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 21);
            else if (((year == 2) && (speed >= 16) || (speed <= 19)))
                fine = INITIAL_FEE;
            if (((year == 2) && (speed >= 20) || (speed <= 24)))
                fine = INITIAL_FEE + (COST_PER_5_OVER);
            if (((year == 2) && (speed >= 25) || (speed <= 29)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 2);
            if (((year == 2) && (speed >= 30) || (speed <= 34)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 3);
            if (((year == 2) && (speed >= 35) || (speed <= 39)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 3);
            if (((year == 2) && (speed >= 40) || (speed <= 44)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 4);
            if (((year == 2) && (speed >= 45) || (speed <= 49)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 5);
            if (((year == 2) && (speed >= 50) || (speed <= 54)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 6);
            if (((year == 2) && (speed >= 55) || (speed <= 59)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 7);
            if (((year == 2) && (speed >= 60) || (speed <= 64)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 8);
            if (((year == 2) && (speed >= 65) || (speed <= 69)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 9);
            if (((year == 2) && (speed >= 70) || (speed <= 74)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 10);
            if (((year == 2) && (speed >= 75) || (speed <= 79)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 11);
            if (((year == 2) && (speed >= 80) || (speed <= 84)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 12);
            if (((year == 2) && (speed >= 85) || (speed <= 89)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 13);
            if (((year == 2) && (speed >= 90) || (speed <= 94)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 14);
            if (((year == 2) && (speed >= 95) || (speed <= 99)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 15);
            if (((year == 2) && (speed >= 100) || (speed <= 104)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 16);
            if (((year == 2) && (speed >= 105) || (speed <= 109)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 17);
            if (((year == 2) && (speed >= 110) || (speed <= 114)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 18);
            if (((year == 2) && (speed >= 115) || (speed <= 119)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 19);
            if (((year == 2) && (speed >= 120) || (speed <= 124)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 20);
            if (((year == 2) && (speed >= 125) || (speed <= 129)))
                fine = INITIAL_FEE + (COST_PER_5_OVER * 21);
            else if (((year == 3) && (speed >= 16) || (speed <= 19)))
                fine = INITIAL_FEE + 50.00;
            if (((year == 3) && (speed >= 20) || (speed <= 24)))
                fine = INITIAL_FEE + 50.00 + (COST_PER_5_OVER);
            if (((year == 3) && (speed >= 25) || (speed <= 29)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 2);
            if (((year == 3) && (speed >= 30) || (speed <= 34)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 3);
            if (((year == 3) && (speed >= 35) || (speed <= 39)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 4);
            if (((year == 3) && (speed >= 40) || (speed <= 44)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 5);
            if (((year == 3) && (speed >= 45) || (speed <= 49)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 6);
            if (((year == 3) && (speed >= 50) || (speed <= 54)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 7);
            if (((year == 3) && (speed >= 55) || (speed <= 59)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 8);
            if (((year == 3) && (speed >= 60) || (speed <= 64)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 9);
            if (((year == 3) && (speed >= 65) || (speed <= 69)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 10);
            if (((year == 3) && (speed >= 70) || (speed <= 74)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 11);
            if (((year == 3) && (speed >= 75) || (speed <= 79)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 12);
            if (((year == 3) && (speed >= 80) || (speed <= 84)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 13);
            if (((year == 3) && (speed >= 85) || (speed <= 89)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 14);
            if (((year == 3) && (speed >= 90) || (speed <= 94)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 15);
            if (((year == 3) && (speed >= 95) || (speed <= 99)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 16);
            if (((year == 3) && (speed >= 100) || (speed <= 104)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 17);
            if (((year == 3) && (speed >= 105) || (speed <= 109)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 18);
            if (((year == 3) && (speed >= 110) || (speed <= 114)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 19);
            if (((year == 3) && (speed >= 115) || (speed <= 119)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 20);
            if (((year == 3) && (speed >= 120) || (speed <= 124)))
                fine = (INITIAL_FEE + 50.00) + (COST_PER_5_OVER * 21);
            else if (((year == 4) && (speed >= 16) || (speed <= 19)))
                fine = INITIAL_FEE + 100.00;
            if (((year == 4) && (speed >= 20) || (speed <= 24)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER);
            if (((year == 4) && (speed >= 25) || (speed <= 29)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 2);
            if (((year == 4) && (speed >= 30) || (speed <= 34)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 3);
            if (((year == 4) && (speed >= 35) || (speed <= 39)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 4);
            if (((year == 4) && (speed >= 40) || (speed <= 44)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 5);
            if (((year == 4) && (speed >= 45) || (speed <= 49)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 6);
            if (((year == 4) && (speed >= 100) || (speed <= 54)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 7);
            if (((year == 4) && (speed >= 55) || (speed <= 59)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 8);
            if (((year == 4) && (speed >= 60) || (speed <= 64)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 9);
            if (((year == 4) && (speed >= 65) || (speed <= 69)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 10);
            if (((year == 4) && (speed >= 70) || (speed <= 74)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 11);
            if (((year == 4) && (speed >= 75) || (speed <= 79)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 12);
            if (((year == 4) && (speed >= 80) || (speed <= 84)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 13);
            if (((year == 4) && (speed >= 85) || (speed <= 89)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 14);
            if (((year == 4) && (speed >= 90) || (speed <= 94)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 15);
            if (((year == 4) && (speed >= 95) || (speed <= 99)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 16);
            if (((year == 4) && (speed >= 100) || (speed <= 104)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER);
            if (((year == 4) && (speed >= 105) || (speed <= 109)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 18);
            if (((year == 4) && (speed >= 110) || (speed <= 114)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 19);
            if (((year == 4) && (speed >= 115) || (speed <= 119)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 20);
            if (((year == 4) && (speed >= 120) || (speed <= 124)))
                fine = (INITIAL_FEE + 100.00) + (COST_PER_5_OVER * 21);

            // finish coding this method

            return fine;
        }

        static void DisplayFine(double fine)
        {
            Console.WriteLine("Fine: {0:C}", fine);
        }

        static char GetUserChoice()
        {
            Console.Write
                ("\nPress \"C\" to [C]ontinue or \"Q\" to [Q]uit: ");
            string userEntry = Console.ReadLine();
            char choice = Convert.ToChar(userEntry);
            Console.WriteLine("------------------------------------");
            return choice;
        }
    }
}

我有一个完整的列表,这些语句的时速高达 125 英里,并且在不同的年份:1 到 4。我正在尝试制作一个程序,该程序接受车辆速度的输入,然后根据速度提供适当的票务信息。

限速为 15 英里/小时。每小时超过限速 5 英里,总计将增加 87.50 美元。第 2 年是大二,因此适用 50.00 美元的折扣。然而,对于第 4 年,总额中增加了 100.00 美元的费用。对于每种速度,我得到相同的总数。为什么?

4

9 回答 9

13

其他人关于运算符优先级的说法似乎是正确的,但我认为这里有一个更大的问题。你真的不应该需要无数的 if 语句来模拟这个问题。我相信你现在已经发现这种方法是不可维护的。试图改变那一堆 if 中的任何东西将是一个真正的痛苦并且非常容易出错。

我要做的第一件事是将折扣计算与罚款计算分开。这样您就不必手动计算每个可能的折扣和罚款组合。这就是我所说的:

static double CalculateFine(int speed, int year)
{
    const double COST_PER_5_OVER = 87.5;
    const int SPEED_LIMIT = 15;
    const double INITIAL_FEE = 75;

    // Should there be a fine at all?
    if (speed > SPEED_LIMIT) {
        // The discount is 50 for each year, scaled so that year 1 is
        // -50, year 2 is 0, and so on.
        double discount = year * 50 - 100;

        // Now calculate the standard fee.
        int feeMultiplier = (speed - SPEED_LIMIT) / 5;
        double fine = feeMultiplier * COST_PER_5_OVER + INITIAL_FEE;

        return discount + fine;
    }
    return 0.;
}

最后,折扣和罚款只合并了一次。真的,这只是弄清楚使用什么公式来计算罚款然后实施。如果罚款以更任意的方式定义,那么表格可能会很有用。

于 2009-04-05T20:37:29.273 回答
1

好吧,这不是一个直接的答案(我认为其他人已经很好地涵盖了这一点),您可能想查看Steve McConnell的Code Complete一书。它包含避免使用上述代码的最佳实践。它可以帮助您完成未来的项目。

于 2009-04-05T20:48:28.717 回答
1

(speed >= 50) || (speed <= 54)

如果您希望这意味着“速度在 50 到 54 之间”,那么您的逻辑就是错误的。你想要和,不是或者。

我不知道这里提供实际答案而不是在那里指导某人的礼仪是什么,但这是你应该瞄准的事情。虽然我没有亲自测试过。

static double CalculateFine(int speed, int year)
{
    const double COST_PER_5_OVER = 87.50;
    const int SPEED_LIMIT = 15;
    const double INITIAL_FEE = 75.00;
    double fine = 0;

    if(speed <= SPEED_LIMIT)
    {
        return 0; // No fine imposed
    }

    fine = INITIAL_FEE;

    // Adjust for the different years
    switch(year) {
        case 1:
            fine -= 50;
            break;
        case 2:
            // nowt
            break;
        case 3:
            fine += 50;
            break;
        case 4:
            fine += 100;
    }

    // Add the remaining fine for each 5 miles over the limit
    // XXX: This is slightly different from yours, in that past 125,
    // it'll still keep adding COST_PER_5_OVER
    int perFiveOver = (int)Math.Floor((speed - SPEED_LIMIT) / 5);
    fine += (perFiveOver * COST_PER_5_OVER);

    return fine;

}
于 2009-04-05T19:24:54.690 回答
0

那些 if 语句让我的眼睛流血了——而且它们也不一致。您在第一个范围内的速度存在错误 - 第一年并且速度为 15 会被罚款。在某些情况下,您使用一大行 if 语句,在其他情况下使用 if/elseif 语句。有区别 - 特别是当您测试速度是否 <= 某个数字时。(一堆带有 || or 子句的 if 语句将分别评估为 true,if/else 语句只会评估第一个)。您可能指的是 && (and) 而不是 || (或)-但是为了每个人的理智,您应该替换那些 if 语句。;)

找出公式,然后编写代码——不是结果。看起来它是[1]:

    const double COST_PER_5_OVER = 87.50;
    const int SPEED_LIMIT = 15;
    const double INITIAL_FEE = 75.00;

    if (speed <= SPEED_LIMIT)
    {
         return 0;
    }

    double yearSurcharge;
    switch (year)
    {
        case 1:
           yearSurcharge = -50;
           break;
        case 2:
           yearSurcharge = 0;
           break;
        case 3:
            yearSurcharge = 50;
            break;
        case 4:
            yearSurcharge = 100;
            break;
        default:
            yearSurcharge = 0;
            break;
    }

    const int NUMBER_OF_FIVE_OVER = 21;
    int numberOfFiveOver = Math.Min((speed - SPEED_LIMIT) % 5; MAX_NUMBER_OF_FIVE_OVER)

    return INITIAL_FEE + yearSurcharge + (numberOfFiveOver * COST_PER_5_OVER);

这可以简化为以下内容:

    if (speed > SPEED_LIMIT) {
         return INITIAL_FEE 
                + (year == 1 ? -50 : year == 3 ? 50 : year == 4 ? 100 : 0) 
                + Math.Min((speed - SPEED_LIMIT) % 5, MAX_NUMBER_OF_FIVE_OVER) * COST_PER_5_OVER;
    } else {
         return 0;
    }

尽管有些人会为年度部分的嵌套三元组争论不休。

[1] 从技术上讲,任何超过 125 的东西都会被罚款 0 美元——但我认为这并不是你真正想要的。

于 2009-04-05T20:10:21.727 回答
0

通常,如果 If 语句具有至少一个或多个“嵌套”If 语句,您将使用 switch 语句......

于 2009-08-08T11:27:23.837 回答
0

嘿,我有点困惑,应该是

((year == 1) && (speed >= 50) && (speed <= 54))

?

于 2009-04-05T19:25:11.770 回答
0

我认为您混淆了运算符优先级和语义。

首先你要说 (speed >=50) && (speed <= 54)

其次,在 C 中 && 具有更高的优先级,所以你的表达方式是:如果 (year==1 AND speed>=50) OR (如果我的速度低于 54)...

第三,您有一对额外的 (),这表明您打算以不同的方式优先处理事物。

最后,我会提到那些有一堆类似的 if 语句的代码写得相当糟糕。实现它的更好方法是使用表或数据结构来表示范围,或者至少是更好的组织。

====

更新:既然你已经发布了代码,看起来你真的在这方面工作太努力了......首先,如果或切换基于年份(应该只有大约 4 年)。对于每一年,调用一个单独的函数来进行计算,这已经更干净了。例如:

if(year==1) return calculateFineForYear1(speed);
if(year==2) return ...

(我不懂 C#,但应该有某种 switch 语句)

现在您可以分别管理每一年。由于您的条件按速度升序排列,您可以执行以下操作:

if(speed<50) return 0;
if(speed<55) return ...;
if(speed<60) return ...;
if(speed<65) return ...

它仍然远非完美,但它已经变得更加清洁和易于管理。

现在,看看你的 ifs,看起来你甚至不需要那么多 ifs,因为你要支付 50 + C*diff,所以为什么不只计算 diff (speed-50) 然后只返回结果计算?

例如:

Int total_above_limit = (speed – SPEED_LIMIT);
Int increments_of_5_above_limit = (total_above_limit)/5
Return ( (INITIAL_FEE – 50) + COST_PER_5_OVER*increments_of_5_above_limit))

(我不懂 C#,我只是猜测语法)

于 2009-04-05T19:26:08.133 回答
0

不确定我 100% 确定您的代码正在尝试做什么,但问题是否取决于逻辑运算符的优先级,即应该是:

if (((year == 1) && ((speed >= 50) || (speed <= 54)))) 罚款 = (INITIAL_FEE - 50.00) + (COST_PER_5_OVER * 7);

注意速度不等式周围的额外括号。

于 2009-04-05T19:26:43.780 回答
0

表驱动的方法在这里应该可以很好地工作。定义表中的值,然后遍历它们以找到匹配的值,然后使用它进行计算。这很好用,您可以轻松添加/编辑/删除条目,而无需接触代码 - 完全没有。

您可以从一个简单的静态分配和定义表开始。如果需要,您可以从另一个源(例如 XML 文件)动态加载表。

于 2009-04-06T01:02:56.750 回答