PoVa
PoVa

Reputation: 1043

The out parameter must be assigned to before control leaves the current methods

I'm very new C# and this is the first time I'm doing anything with a list, so this might be a very dumb question... I'm trying to read data from a file to a list that consists of Tourist objects. As I understand I need to assign something to tourists list before I add objects to it, but I'm not sure how to do that.

class Tourist
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public double Contributed { get; set; }

    public Tourist(string firstName, string lastName, double money)
    {
        FirstName = firstName;
        LastName = lastName;
        Contributed = money * 0.25;
    }
}

class Program
{
    static void Main(string[] args)
    {
        List<Tourist> tourists = new List<Tourist>();

        ReadData(out tourists);
    }

    static void ReadData(out List<Tourist> tourists)
    {
        const string Input = "..\\..\\Duomenys.txt";

        string[] lines = File.ReadAllLines(Input);
        foreach (string line in lines)
        {
            string[] values = line.Split(';');
            string firstName = values[0];
            string lastName = values[1];
            double money = Double.Parse(values[2]);
            tourists.Add(new Tourist(firstName, lastName, money));
        }
    }
}

Upvotes: 4

Views: 1945

Answers (3)

MakePeaceGreatAgain
MakePeaceGreatAgain

Reputation: 37050

You have to provide a value for your out-parameter before leaving the method

static void ReadData(out List<Tourist> tourists)
{
    const string Input = "..\\..\\Duomenys.txt";
    tourists = new List<Tourist>();

    string[] lines = File.ReadAllLines(Input);
    foreach (string line in lines)
    {
        string[] values = line.Split(';');
        string firstName = values[0];
        string lastName = values[1];
        double money = Double.Parse(values[2]);
        tourists.Add(new Tourist(firstName, lastName, money));
    }
}

However as you´re passing a List<T> which is a reference-type you don´t need the out.keyword as modifications to the object that you´re referencing are reflected in all references.

So after calling ReadData the list you´ve provided will change also:

var tourists = new List<Tourist>();
ReadData(toursists);  // this changes the elements within the list
// do something with the list

Upvotes: 1

slawekwin
slawekwin

Reputation: 6310

Parameters with out need to be assigned to in the body of the method and do not get their value carried over from the call site. Quoting msdn:

Within a method, just like a local variable, an output parameter is initially considered unassigned and must be definitely assigned before its value is used.

In your case there are three ways to solve it:

First, you can move assignment from caller to the method:

static void Main(string[] args)
{
    List<Tourist> tourists;
    ReadData(out tourists);
}

static void ReadData(out List<Tourist> tourists)
{
    tourists = new List<Tourist>();
    //...
}

Second, you can change your declaration to skip out in the declaration entirely, which will carry the initiated value to the method and lift the requirement to assign it in that method.

Last option (and the best one IMO, in terms of readability) is to make the list a return value instead of out parameter:

static void Main(string[] args)
{
    List<Tourist> tourists = ReadData();
}

static List<Tourist> ReadData()
{
    List<Tourist> tourists = new List<Tourist>();
    //...
    return tourists;
}

Upvotes: 2

Ren&#233; Vogt
Ren&#233; Vogt

Reputation: 43906

By declaring a parameter as out you "promise" the caller (and the compiler) that your method will set a value to the variable provided as argument for that parameter.

Because you promise it, every path through your method must assign a value to this parameter.

Your method does not assign a value to tourists. This may actually lead to a NullReferenceException at tourists.Add(...) if the method gets called with a null reference.

To me it seems you can ommit the out keyword as you initialize tourists already in Main. Note that ReadData only modifies the content of the list, not the reference to it stored in the tourists variable. Since you don't want to change that reference (the variable's value), you don't need the out keyword.

If you want ReadData to initialize it, you need to add the line

tourists = new List<Tourist>()

in ReadData before the foreach loop.


As your code stands, the better solution is to ommit any parameter to ReadData and let the method return the list instead:

static List<Tourist> ReadData()
{
    // create list
    List<Tourist> tourists = new List<Tourist>();

    const string Input = "..\\..\\Duomenys.txt";       

    string[] lines = File.ReadAllLines(Input);
    foreach (string line in lines)
    {
        // shortened for brevity
        tourists.Add(new Tourist(firstName, lastName, money));
    }

    return tourists; // return newly created list
}

And use this in Main like:

static void Main(string[] args)
{
    List<Tourist> tourists = ReadData();
}

Upvotes: 5

Related Questions