0

I don't think my question is a duplicate because I am not asking how to convert Lists in to CSVs. But:
I am trying to convert a list into a comma-delimited csv file.
However, some fields contain commas and semicolons.
A column will be split into at least two columns when there is a comma.

My codes:

public void SaveToCsv<T>(List<T> listToBeConverted)
{
    var lines = new List<string>();
    IEnumerable<PropertyDescriptor> props = TypeDescriptor.GetProperties(typeof(T)).OfType<PropertyDescriptor>();
    //Get headers
    var header = string.Join(",", props.ToList().Select(x => x.Name)); 
    //Add all headers
    lines.Add(header);
    //LinQ to get all row data and add commas to serperate them
    var valueLines = listToBeConverted.Select(row => string.Join(",", header.Split(',').Select(a => row.GetType().GetProperty(a).GetValue(row, null))));
    //add row data to List
    lines.AddRange(valueLines);
    ...
}

How do I modify the LinQ statment to add double quotes to the start and the end of the string when it is System.String?

AsM
  • 91
  • 1
  • 10
  • 2
    **Using a CSV library** will make your experience considerably more comfortable. Exactly this has been solved several times by people that are more clever than you and me combined. They are extensively tested and used in the field. Yes, we don't like 3rd party dependencies. But sometimes, it is better to stand on the shoulders of giants. – Fildor Nov 18 '22 at 07:30
  • 1
    I absolutely agree with you! However, I think this is a good chance for me to learn more about C# and LinQ coding! – AsM Nov 18 '22 at 08:59
  • If that is your goal here, then that's totally fine, of course. – Fildor Nov 18 '22 at 09:43

2 Answers2

2

Use property info for this purpose.

void SaveToCsv<T>(List<T> listToBeConverted)
{
    var lines = new List<string>();
    IEnumerable<PropertyDescriptor> props = TypeDescriptor.GetProperties(typeof(T)).OfType<PropertyDescriptor>();
    //Get headers
    var header = string.Join(",", props.ToList().Select(x => x.Name));
    //Add all headers
    lines.Add(header);
    //LinQ to get all row data and add commas to serperate them
    var valueLines = listToBeConverted.Select(row => string.Join(",", props.Select(x =>
    {
        var property = row.GetType().GetProperty(x.Name);
        if (property.PropertyType == typeof(string))
            return $"\"{property.GetValue(row, null)}\"";
        return property.GetValue(row, null);
    })));
    //add row data to List
    lines.AddRange(valueLines);
    ...
}
  • Thank you Sasha! It works perfectly! Also, we can change the content of the `if`. If the field contains commas and semicolons, we can clone the object to a string, and return `property.GetValue(row, null)`. – AsM Nov 18 '22 at 08:57
0

CSV is Comma-Separated Values, but the separator is based on your default system separator! Use a system separator for columns and use the end-line for rows.

you can find your system default in this way:

Open Control panel

enter image description here

open clock and region

enter image description here

Click on Aditional Setting

enter image description here

You can see and change the system's default separator

enter image description here

Hadi
  • 100
  • 1
  • 11
  • If I want to change the separator, I can just change it in my codes. In this case, I want to keep comma as the separator. – AsM Nov 18 '22 at 08:59