-1

I have a file in my project folder containing the data for properties in a Vehicle class. If the class was hardcoded into the XAML it would look like this:

  Vehicle v1 = new Car() { Make = "Ford", Model = "Fiesta", Price = 10000, Year = "1999", Colour = "Red", Mileage = 40000, Description = "Lovely red car, 4 wheel, optional steering wheel.", VehicleType = "Car" };
  VehicleList.Add(v1);

I don't want to hardcode this class object in, Instead I want to read it from a .txt file, each part separated by a comma ',' and place these into each property and add that vehicle into the Vehicle List<> 'VehicleList' and then display this new read list into a listbox.

Both the hardcode and the .txt follow the same structure with the hardcode containing the variable names and the .txt file containing just the data.

Here is what I have so far, as you can see I tried using System.IO however I am open to alternative methods.

        private void Button_Click(object sender, RoutedEventArgs e)
    {
        string location = @"PATH";
        VehicleList = File.ReadAllLines(location).ToList();

        var logFile = File.ReadAllLines(location);
        foreach (var v[i] in logFile) VehicleList.Add(s);
    }
}
Legend
  • 71
  • 1
  • 7

1 Answers1

0
public static List<Car> FromTextFile(string fileName)
{
    var lines = File.ReadAllLines(fileName);

    var cars = new List<Car>();
    foreach (var line in lines)
    {
        var car = FromLine(line);
        if (car == null)
            continue;

        cars.Add(car);
    }

    return cars;
}

private static Car FromLine(string line)
{
    var values = line.Split(',');

    if (values.Length != 8) // There is no specification on what to do, if the amount of items is not sufficient.
        return null;

    // There is also no specification on what order to use, or how to map the ordering.
    return new Car
    {
        Make = values[0],
        Model = values[1],
        // There is also no specification on how to handle in-correct formats.
        // This assumes the Price property to be type of int.
        Price = int.Parse(values[2]), 
        Year = values[3],
        Colour = values[4],
        // Again; how to handle in-correct formats?
        Mileage = int.Parse(values[5]),
        Description = values[6],
        VehicleType = values[7]
    };
}

This code should do what you described. Please be aware of the limitations of this code;

  • It expects a file that contains some lines, in comma seperated format.
  • It expects lines to contain 8 non-empty items, otherwise those lines will not be mapped.
  • It assumes the comma-seperated items to be exactly in this order; Make, Model, Price, Year, Colour, Mileage, Description, VehicleType.
  • It will not handle in-correct formats for converted types (e.g int). Because you did not ask so.

Keep in mind that this is not a desired code, it is not well written.

Now, as to your code;

Firstly, you've two different values for lines. I don't know why. One of them should be ok.

Second, you try to loop through one of them using foreach, but it doesn't work like that. You don't give or take an index from the foreach loop. The correct what is just foreach (TYPE VARIABLE_NAME in COLLECTION). So your code would be foreach (var v /* not v[i] */ in logFile) // ...

And then you add this to a list which contains those seperated lines again. At the end of the day, you have a list that contains the same lines twice. What you should have done in the adding part is, you should have converted the line to a Car object. Now how you do that, is absolutely up to you. Here are some question that comes to my mind, when the task is something such as mapping a string collection to an object.

  • What do I do if some members do not exist? (i.e when there is 5 items in the line, even though we have 8 properties)
  • How do I know which property to map the i'th item? What is the ordering? Do I get it from a "Columns" line? Do I just assume some ordering of my desire? How do I handle, if the user does not follow those rules?
  • What do I do, when there is something wrong about formatting of some of the members?

Now, this is not really an un-common problem. Everyone somehow needs to transport the data from place A to place B. For your specific instance, it is from disk storage, to memory, in the form of an object.

How do people solve these sorts of problem? They invent generic ways of "serialization" and "deserialization". What are some examples? The most known ones and the most used ones that comes to my mind are XML (eXtensible Markup Language) and JSON (JavaScript Object Notation). What do these actually do? They serialize programming objects to non-binary string formats. Here is an example XML output for your Car class.

<?xml version=\"1.0\" encoding=\"utf-16\"?>
<Car xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">
  <Make>Ford</Make>
  <Model>Fiesta</Model>
  <Price>10000</Price>
  <Year>1999</Year>
  <Colour>Red</Colour>
  <Mileage>40000</Mileage>
  <Description>Lovely red car, 4 wheel, optional steering wheel.</Description>
  <VehicleType>Car</VehicleType>
</Car>

Generated with this simple code;

var car = new Car
{
    Make = "Ford",
    Model = "Fiesta",
    Price = 10000,
    Year = "1999",
    Colour = "Red",
    Mileage = 40000,
    Description = "Lovely red car, 4 wheel, optional steering wheel.",
    VehicleType = "Car"
};

var serializer = new XmlSerializer(typeof(Car));

// https://stackoverflow.com/questions/2434534/serialize-an-object-to-string
using (StringWriter textWriter = new StringWriter())
{
    serializer.Serialize(textWriter, car);
    var output = textWriter.ToString();
}

And this is, how you would easily read "Car"s from a text file, if it was formatted correctly;

var serializer = new XmlSerializer(typeof(List<Car>));
// If your file should contain one car and one car only, you should change the above line to;
// var serilizer = new XmlSerializer(typeof(Car));

using (var reader = File.OpenRead(@"PATH"))
{
    var cars = (List<Car>)serializer.Deserialize(reader);
    reader.Close();
}

Similar code can be written for JSON. But I think you get the idea.

In short, most of the times, XML, JSON or a similar generic format is sufficient. When they are not, you can develop your very own format. But comma-seperated line is a very simplistic way of doing serialization. The reasons are exactly my question (see above). And XML, JSON answers those questions easily. Implementations do a very good job as well, most of the time.


Edit

Here is an answer to a very similar question. The answer to that question would high likely also answer your question. How to split csv whose columns may contain ,

Community
  • 1
  • 1
welrocken
  • 266
  • 1
  • 9
  • Thanks very much for the detailed response, so what your saying is that the first code works but isnt great. So the second code is Xaml and the rest is XAML.cs... am I right? – Legend Feb 26 '17 at 15:55
  • Not exactly, the second code is what you should write in your method (i.e inside `void Button_Click(object, RoutedEventArgs)`). For example; `private void Button_Click(object sender, RoutedEventArgs e) { var serializer = new XmlSerializer(typeof(List)); // If your file should contain one car and one car only, you should change the above line to; // var serilizer = new XmlSerializer(typeof(Car)); using (var reader = File.OpenRead(@"PATH")) { var cars = (List)serializer.Deserialize(reader); reader.Close(); } }` – welrocken Feb 26 '17 at 16:00
  • I have tried to play around with this but to no avail, I have entered the above comment inside the button_click. I am getting an execption saying that there is an error in the XML file just before the reader.Close – Legend Feb 26 '17 at 20:43
  • **And this is, how you would easily read "Car"s from a text file, if it was formatted correctly;**. I will give you an example .txt file to work with as soon as possible. – welrocken Feb 26 '17 at 20:49
  • Thanks, just to let you know that the .txt file is formatted the same way I have the hardcode properties. Only difference between the 2 are that the .txt does not included the property names, just the data. – Legend Feb 26 '17 at 21:13
  • If your text file is formatted like that, I don't think you can use XML (de)serialization for your task. Try the solution I have provided in the beginning of my answer. It's not a very good solution, but you can't really get "very good" with delimited text as a serialization/deserialization solutions. The only place where it could be used is, where you are sure that your data only contains primitive types (your Car class only contains primitive typed properties for instance). You can use .csv format, it is similar. You may even find a Nuget package for csv parsing. – welrocken Feb 26 '17 at 22:40
  • I get what you mean I found another method through streamreader, but I did learn about serialization/deserialization. :) – Legend Feb 28 '17 at 00:09