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 ,