0

I'm working on my first real c# project and I have faced a problem with my way of creating List based on a Class, which I have no idea how to solve.

I’m trying to write some code, which takes an input file (txt/csv) of multiple constructions with multiple layers, put it into my program, and later write the constructions into a new txt/csv file.

When having the same numbers of layers, it works fine. But when the constructions have different numbers of layers it causes trouble and I get a “System.IndexOutOfRangeException”. My question is: Can I make the Class which I’m basing my List on, dynamic (I don’t know if it is the technical term), so it work with different numbers of inputs? Both when Adding the construction to the program and when I write it to a new file?

My code is:

class Program
{
    static void Main(string[] args)
    {
        // Filepath for the input and output file
        string filePathIn_constructions = @"C:\Library\Constructions.txt";
        string filePathOut = @"C:\Library\EPlus_Inputfile.txt";

        // Creating a list of constructions based on the class. The list is made from the file "filePathIn_constructions"
        List<Construction> allConstructions = new List<Construction>();
        List<string> lines_constructions = File.ReadAllLines(filePathIn_constructions).ToList(); // add it to a list

        // Adding all the data from the fil to the variable "allConstructions"
        foreach (var line in lines_constructions)
        {
            string[] entries = line.Split(',');

            Construction newConstruction = new Construction();
            newConstruction.EIndex = entries[0];
            newConstruction.Name = entries[1];
            newConstruction.Layer1 = entries[2];
            newConstruction.Layer2 = entries[3];
            newConstruction.Layer3 = entries[4];
            newConstruction.Layer4 = entries[5];
            newConstruction.Layer5 = entries[6];
            
            allConstructions.Add(newConstruction); // Add it to our list of constructions
        }

        List<string> output = new List<string>();

        foreach (var x in allConstructions) // Printing the new 
        {
            output.Add($"{x.EIndex}, {x.Name}, {x.Layer1}, {x.Layer2}, {x.Layer3}, {x.Layer4}, {x.Layer5}");
            
        }
        File.WriteAllLines(txtFilePathOut, output);
    }
}

My Class for the Constructions is

public class Construction
{
    public string EIndex { get; set; }
    public string Name { get; set; }
    public string Layer1 { get; set; }
    public string Layer2 { get; set; }
    public string Layer3 { get; set; }
    public string Layer4 { get; set; }
    public string Layer5 { get; set; }      
}

An example of a input/output file could be

Construction,ConcreteWall,Concrete;
Construction,Brickwall1,Birck,Isulation,Brick;
Construction,Brickwall2,Birck,AirGap,Isulation,Brick;
Construction,Wood/Concrete Wall,Wood,Isulation,Concrete,Gypson;
Construction,Wood Wall,Wood,AirGap,Gypson,Isulaiton,Gypson;

I hope someone can help. Thanks.

Edit: I have to be able to excess the construction Name seperatly, because i'm using it to do some sorting of the.

vHartvig
  • 3
  • 2
  • 1
    Why not a `Construction` having a `List` or `List` because a `Layer` is a `string` currently? this would resolve your issue immediately. – Hazrelle Nov 26 '21 at 12:38
  • As soon as you need numbered properties, you're doing it wrong. You need a `List Layers { get; set; }`. Or you're going to need an `if (entries.Count >= ...)` around each array access. – CodeCaster Nov 26 '21 at 12:43
  • Chill guys he says it's his first real project, I assume he's relatively new to C# – Error 404 Brain not found Nov 26 '21 at 12:46
  • 1
    Yes, as Error404Brainnotfound says, i'm very new, so i don't know a lot of ways to do stuff. @Hazrelle: Because this solution is based on a Youtube video of something similar, but that does not work anymy so that is why i'm asking here for advise :) If what you suggest would work it sound good, but can you give an example on how you would do it? Because i'm not sure I understand how to. – vHartvig Nov 26 '21 at 13:34
  • Provide both current input and desired output we may help ... – Hazrelle Nov 26 '21 at 13:37

2 Answers2

0

It is because you are trying to reach a cell of an array that doesn't exist (documentation)

In your input/output file you have lines that have between 3 and 7 values, and you are building an array entries out of those values. This means that you will have arrays with between 3 and 7 cells

The problem is that right after creating those arrays you try to access on every array the cells 0, 1, 2... up to the 7th, even for arrays that have only 3 cells!

What you could do to fix this in a simple way is to add columns to have the same number of separator on each lines (you defined the separator of your lines as column with line.Split(',')). This way, every arrays that you will create will always have 7 cells, even if the value inside is null

  • Thank you very much for the quick reply. I have tryed that, and it worked for some time. But the problem is that, I have to use the output file, as an inputfile for another program (EnergyPlus), which does not work, when i add emty fields into it. So i have to find anonther way, without emty columns – vHartvig Nov 26 '21 at 13:25
  • What you could do to solve that is to check if the cell is out of bonds before assigning the value, **BUT** as you'll learn to code better in C# you'll learn that this is miles away from being a good and proper solution. The code would be : `newConstruction.EIndex = entries.length >= 0 ? entries[0] : "";` , then just increase 0 to 1 for `newConstruction.Name` (`entries.length >= 1 ? entries[1]`), to 2 for `newConstruction.Layer1`, and keep increasing till you reach `newConstruction.Layer5`. I repeat, **this is not a proper solution**, just something simple to understand – Error 404 Brain not found Nov 26 '21 at 13:38
0
public class Construction
{
    public string EIndex { get; set; }
    public string Name { get; set; }
    public List<string> Layers { get; set; } = new List<string>();     
}

        foreach (var line in lines_constructions)
        {
            string[] entries = line.Split(',');

            Construction newConstruction = new Construction();
            newConstruction.EIndex = entries[0];
            newConstruction.Name = entries[1];
            for (int i=2; i < entries.Length; i++) {
               newConstruction.Layers.Add(entries[i]); 
            }
            
            allConstructions.Add(newConstruction);
        }

        foreach(var x in allConstuctions) {
           File.AppendAllText(output, $"{x.EIndex}, {x.Name}, {string.Join(", ", x.Layers)}");
        }

Hazrelle
  • 758
  • 5
  • 9
  • As poster said, he's new to C#, i don't know if the List is a good idea for this reason (otherwise it clearly would be) – Error 404 Brain not found Nov 26 '21 at 13:52
  • 1
    This is to keep the spirit of the OP :) Else a simple `Regex.Replace(line, ";", ""); Regex.Replace(line, ",", ", ");` would be sufficient for the task. – Hazrelle Nov 26 '21 at 14:02
  • Brilliant, it was what i needed! I works now in a much better way. Thank you Hazrelle and Error 404 Brian not found! :D Just to learn as much as possible and understand. The solution with Regex.Replace - Would that have been posible to use together with my original solution, and just removed everything after '";"'? – vHartvig Nov 26 '21 at 14:50
  • With `Regex` you even not need a class. Lines are already an object of types `string`. Changing a format to another format is sometime easy with simple methods. – Hazrelle Nov 26 '21 at 14:55