What does “Use of unassigned local variable” mean?

2019-01-01 02:20发布

问题:

I keep getting this error for annualRate, monthlyCharge, and lateFee.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Lab_5___Danny_Curro
{
    class Program
    {
        static void Main(string[] args)
        {
            string firstName;
            string lastName;
            int accNumber;
            string creditPlan;
            double balance;
            string status;
            Boolean late = false;
            double lateFee;
            double monthlyCharge;
            double annualRate;
            double netBalance;


            Console.Write(\"Enter First Name: \");
            firstName = Console.ReadLine();

            Console.Write(\"Enter Last Name: \");
            lastName = Console.ReadLine();

            Console.Write(\"Enter Account Number: \");
            accNumber = Convert.ToInt32(Console.ReadLine());


            Console.Write(\"Enter Credit Card Plan Number[Blank Will Enter Plan 0]: \");
            creditPlan = Console.ReadLine();

            Console.Write(\"Enter Balance: \");
            balance = Convert.ToDouble(Console.ReadLine());

            Console.Write(\"Is This Account Late?: \");
            status = Console.ReadLine().Trim().ToLower();

            if (creditPlan == \"0\")
            {
                annualRate = 0.35;  //35%
                lateFee = 0.0;
                monthlyCharge = balance * (annualRate * (1 / 12));
                return;
            }

            if (creditPlan == \"1\")
            {
                annualRate = 0.30;  //30%
                if (status == \"y\")
                {
                    late = true;
                }

                else if (status == \"n\")
                {
                    late = false;
                }
                if (late == true)
                {
                    lateFee = 25.00;
                }
                monthlyCharge = balance * (annualRate * (1 / 12));
                return;
            }
            if (creditPlan == \"2\")
            {
                annualRate = 0.20;  //20%
                if (status == \"y\")
                {
                    late = true;
                }

                else if (status == \"n\")
                {
                    late = false;
                }
                if (late == true)
                {
                    lateFee = 35.00;
                }
                if (balance > 100)
                {
                    monthlyCharge = balance * (annualRate * (1 / 12));
                }
                else
                {
                    monthlyCharge = 0;
                }
                return;
            }
            if (creditPlan == \"3\")
            {
                annualRate = 0.15;  //15%
                lateFee = 0.00;

                if (balance > 500)
                {
                    monthlyCharge = (balance - 500) * (annualRate * (1 / 12));
                }
                else
                {
                    monthlyCharge = 0;
                }
                return;
            }
            netBalance = balance - (lateFee + monthlyCharge);


            Console.WriteLine(\"Name: \\t\\t\\t {0}  {1}\", firstName, lastName);
            Console.WriteLine(\"Account Number: \\t{0}\", accNumber);
            Console.WriteLine(\"Credit Plane: \\t\\t{0}\",creditPlan);
            Console.WriteLine(\"Account Late: \\t\\t{0}\", late);
            Console.WriteLine(\"Balance: \\t\\t{0}\", balance);
            Console.WriteLine(\"Late Fee: \\t\\t{0}\", lateFee);
            Console.WriteLine(\"Interest Charge: \\t{0}\", monthlyCharge);
            Console.WriteLine(\"Net Balance: \\t\\t{0}\",netBalance);
            Console.WriteLine(\"Annual Rate: \\t\\t{0}\", annualRate);
            Console.ReadKey();
        }
    }
}

回答1:

The compiler isn\'t smart enough to know that at least one of your if blocks will be executed. Therefore, it doesn\'t see that variables like annualRate will be assigned no matter what. Here\'s how you can make the compiler understand:

if (creditPlan == \"0\")
{
    // ...
}
else if (creditPlan == \"1\")
{
    // ...
}
else if (creditPlan == \"2\")
{
    // ...
}
else
{
    // ...
}

The compiler knows that with an if/else block, one of the blocks is guaranteed to be executed, and therefore if you\'re assigning the variable in all of the blocks, it won\'t give the compiler error.

By the way, you can also use a switch statement instead of ifs to maybe make your code cleaner.



回答2:

Change your declarations to this:

double lateFee = 0.0;
double monthlyCharge = 0.0;
double annualRate = 0.0;

The error is caused because there is at least one path through your code where these variables end up not getting set to anything.



回答3:

Because if none of the if statements evaluate to true then the local variable will be unassigned. Throw an else statement in there and assign some values to those variables in case the if statements don\'t evaluate to true. Post back here if that doesn\'t make the error go away.

Your other option is to initialize the variables to some default value when you declare them at the beginning of your code.



回答4:

Give them a default value:

double lateFee=0.0;
double monthlyCharge = 0.0;
double annualRate = 0.0;

Basically, all possible paths don\'t initialize these variables.



回答5:

Your assignments are all nested within your conditional if blocks which means that there is potential for them to never be assigned.

At the top of your class, initialise them to 0 or some other value



回答6:

There are many paths through your code whereby your variables are not initialized, which is why the compiler complains.

Specifically, you are not validating the user input for creditPlan - if the user enters a value of anything else than \"0\",\"1\",\"2\" or \"3\", then none of the branches indicated will be executed (and creditPlan will not be defaulted to zero as per your user prompt).

As others have mentioned, the compiler error can be avoided by either a default initialization of all derived variables before the branches are checked, OR ensuring that at least one of the branches is executed (viz, mutual exclusivity of the branches, with a fall through else statement).

I would however like to point out other potential improvements:

  • Validate user input before you trust it for use in your code.
  • Model the parameters as a whole - there are several properties and calculations applicable to each plan.
  • Use more appropriate types for data. e.g. CreditPlan appears to have a finite domain and is better suited to an enumeration or Dictionary than a string. Financial data and percentages should always be modelled as decimal, not double to avoid rounding issues, and \'status\' appears to be a boolean.
  • DRY up repetitive code. The calculation, monthlyCharge = balance * annualRate * (1/12)) is common to more than one branch. For maintenance reasons, do not duplicate this code.
  • Possibly more advanced, but note that Functions are now first class citizens of C#, so you can assign a function or lambda as a property, field or parameter!.

e.g. here is an alternative representation of your model:

    // Keep all Credit Plan parameters together in a model
    public class CreditPlan
    {
        public Func<decimal, decimal, decimal> MonthlyCharge { get; set; }
        public decimal AnnualRate { get; set; }
        public Func<bool, Decimal> LateFee { get; set; }
    }

    // DRY up repeated calculations
    static private decimal StandardMonthlyCharge(decimal balance, decimal annualRate)
    { 
       return balance * annualRate / 12;
    }

    public static Dictionary<int, CreditPlan> CreditPlans = new Dictionary<int, CreditPlan>
    {
        { 0, new CreditPlan
            {
                AnnualRate = .35M, 
                LateFee = _ => 0.0M, 
                MonthlyCharge = StandardMonthlyCharge
            }
        },
        { 1, new CreditPlan
            {
                AnnualRate = .30M, 
                LateFee = late => late ? 0 : 25.0M,
                MonthlyCharge = StandardMonthlyCharge
            }
        },
        { 2, new CreditPlan
            {
                AnnualRate = .20M, 
                LateFee = late => late ? 0 : 35.0M,
                MonthlyCharge = (balance, annualRate) => balance > 100 
                    ? balance * annualRate / 12
                    : 0
            }
        },
        { 3, new CreditPlan
            {
                AnnualRate = .15M, 
                LateFee = _ => 0.0M,
                MonthlyCharge = (balance, annualRate) => balance > 500 
                    ? (balance - 500) * annualRate / 12
                    : 0
            }
        }
    };


回答7:

The compiler is saying that annualRate will not have a value if the CreditPlan is not recognised.

When creating the local variables ( annualRate, monthlyCharge, and lateFee) assign a default value (0) to them.

Also, you should display an error if the credit plan is unknown.



回答8:

Not all code paths set a value for lateFee. You may want to set a default value for it at the top.



回答9:

You don\'t assign values outside of the if statements ... and it is possible that credit might be something other than 0, 1, 2, or 3, as @iomaxx noted.

Try changing the separate if statements to a single if/else if/else if/else. Or assign default values up at the top.



回答10:

If you declare the variable \"annualRate\" like

class Program {

**static double annualRate;**

public static void Main() {

Try it..