C# Lists and Files
The course is part of this learning path
This course uses file reading and writing as a vehicle to illustrate important data validation concepts when mapping text data to objects and receiving user input. It demonstrates many of the essential elements present in business applications, that is: ingesting data from an external source, enabling users to modify that data, and saving the data back to permanent storage.
Robust and well-designed apps, especially concerning the user interface, need to validate input in terms of data format and applicability and provide feedback when entered data is not appropriate. We round off the course by implementing the data access layer design pattern that will enable the code to be easily adapted to other data sources.
- Read planet data from a text file into a list of planet objects within a solar system object
- Create a basic command-line user interface with data validation and feedback that writes updated planet data back to file
- Take the file reading and writing functionality and split it out into a class that returns planet objects so you can easily change data sources in the future
This course is ideal for anyone who already has some basic knowledge of C# and is looking to expand on that by learning about lists and files within the programming language.
The ideal prerequisite for this course is our C# Loops Deep Dive course, but if you know what the .NET List class is and how to create one, then you’ll be able to follow along with these lectures and demonstrations.
Demo source code: https://github.com/cloudacademy/csharp-lists-and-files
If we’re going to read a file we also need to be able to write one. In this demo I want to write the contents of a text file back to disk after it’s been modified. I’ll state upfront that the actual writing or saving the file to disk is one line of code. The real work is preparing and validating the data for writing as well as the code for accepting user input.
I’m going to modify the program that prints planets’ names and distance from the sun. We’ll enable the user to update a planet’s distance from the sun property and save the modified solar system to disk. The new functionality will involve 3 distinct pieces of code. In program.cs add lines to prompt for, and accept user input. The SolarSystem class will get two new methods; UpdatePlanet to update the distance from the sun property of the appropriate planet and Save, to save the planets back to the text file.
In program.cs, I’ll add a console.Write statement asking for the name of the planet to modify. Write instead of WriteLine will allow us to type immediately after the prompt – note the space after the colon. Console.ReadLine will read in any user input and return it as a string up to when the enter key is pressed. The string variable planetName will be whatever the user has typed after the prompt. Next, I’ll have a prompt for the distance from the sun and a ReadLine storing the input into the string variable: distance. The planet class property DistanceFromSun is an integer, but distance is a string, and in the console we have no way to restrict what a user can type, so we need to make sure whatever they enter is valid.
I’m going to use the TryParse method of the int class. TryParse takes two parameters; the value we want to convert to an int and the out parameter is the converted integer value. The method returns a Boolean value, true or false, indicating whether the conversion has been successful. Methods and functions always have a return type even if it is void, but sometimes you need a method to return more than one value. You could do this with a class and multiple properties or using out parameters. An out parameter has a value assigned to it within its method, and the variable used as the out parameter when calling the method can be used after the method has finished executing. I’ll declare an int variable called km that will be the distance string converted to an int. The bool return value will tell me if the conversion has been successful.
Over to the SolarSystem class to add an UpdatePlanet method that I’ll create from a copy of AddPlanet. The first thing we need to do is find out which planet we’re updating, so we’ll use a foreach loop to cycle through the planets list until we find the one where the names match. I’ll need to change the method’s parameter type from planet to string, and I’ll need a parameter for updating the DistanceFromSun property. We need to know if we have found a match for the planet name we want to update for two reasons. One, there is no point in saving the file if we haven’t made any changes because the user didn't type a proper planet name. Two, if they misspelled the planet's name, we want to tell them. I'll use planetFound to store the value of the planet name comparison, and if planetFound is true, update the DistanceFromSun property of the planet object with the distance parameter. Having found the correct planet, there's no need to carry on looking at the others, so I'll break out of the foreach loop with the break statement. I'll return the planetFound value so we can take appropriate actions at the user interface. If we find the planet, we also want to save the updated solar system. The save functionality will go in a separate method, which I'll call save – funnily enough. The first issue is I don't have a file to save the planets into. The ReadFromFile method takes in the file name, but it's not saved. I'll create a protected member called _fileName to use in the Save method and assign the file name to it in ReadFromFile.
The .NET method File.WriteAllLines will save the text to our filename file. The next issue is correctly formatting the planets list data into a string array required by WriteAllLines. I'll declare a local string array variable called planets and set its size to planets.count. The text file format is planet name, distance from sun, so I'll use string interpolation to build the text and cycle through the planets list assigning each planet to the corresponding string array element. The file format is planet name comma and then distance from sun, so I'll format each line using string interpolation. Now I can use the planets strings array as the second parameter to WriteAllLines. I've just noticed an issue with the planetName comparison in UpdatePlanet. C# is case sensitive, so if the user doesn't type the planet name precisely, i.e., proper case, then it won't be found. I'll use the string method ToLower to compare lowercase versions of the names.
Let's use the planet update functionality in the program. First, let's make sure distance is an int value by testing the isn’t bool variable and telling the user if it isn't before doing anything. If it is a valid number, let's update the planet by name with the new distance. Remember. UpdatePlanet returns the planetFound value, so based on the planet being found and updated, we can then call SolarSystem.Save. I'll write out the updated solar system so we can see the change. If the planet is not found we want to tell the user if they have mistyped the planet name, so display the message planetName is not in the solar system. Before running the program within VS Code, we need to make a small change to launch.json. Running the app in the default internal console won't allow us to type responses to the program's prompts. I'll change the console to integratedTerminal. Okay, let's save and run. Switching over to the terminal window, we can see the planets and the prompt. I'll enter Earth and 201, and sure enough, Earth's distance has been updated, and checking planets.txt, the new value has been written to file. Let's test the validation by entering mars bar as a planet name. Unfortunately, there is no mars bar planet. What about the number validation? I'll enter far, far away for Neptune's distance, and we're correctly told that's not an integer.
In this demo, we've not only saved text to a file, but we've learned about out parameters, reading user input from the console, but most importantly, what to look at when validating user input and giving feedback when the input is incorrect.
Hallam is a software architect with over 20 years experience across a wide range of industries. He began his software career as a Delphi/Interbase disciple but changed his allegiance to Microsoft with its deep and broad ecosystem. While Hallam has designed and crafted custom software utilizing web, mobile and desktop technologies, good quality reliable data is the key to a successful solution. The challenge of quickly turning data into useful information for digestion by humans and machines has led Hallam to specialize in database design and process automation. Showing customers how leverage new technology to change and improve their business processes is one of the key drivers keeping Hallam coming back to the keyboard.