5

I have list of objects type Person. This class has many properties and I need them all in a comma separated list so I can use it later for Csv file.

I've managed this with foreach and adding each property, separating it with commas manual, etc.

const string commaSeparator = ",";
foreach (var item in individualsInformation)
{
    csv.AppendLine(item.ReferenceNumber + commaSeparator + item.FirstName + commaSeparator +
                   item.Surname + commaSeparator + item.MiddleName + commaSeparator +
                   item.Address1 + commaSeparator + item.Address2 + commaSeparator + 
                   item.Address3 + commaSeparator + item.Address4 + commaSeparator + 
                   item.City + commaSeparator + item.PostalCode + commaSeparator +
                   item.Country + commaSeparator + item.DateOfBirth.ToString() + commaSeparator +
                   item.ID + commaSeparator + item.Gender + commaSeparator +
                   item.Component + commaSeparator + item.NationalID + commaSeparator + 
                   item.SubSystemID + commaSeparator + item.System);
}

Then I've realized that there is much efficient way, by using string.Join

This does not work of course:

string joined = string.Join(",", listOfPersons);

And if I go by selecting property like this:

string joined = string.Join(",", listOfPersons(x => x.Id);

I get comma separated list only for that property of course.

Is there some more efficient way for getting each property separated by comma?

2
  • 1
    Stop trying to reinvent the wheel. Check the answer here Commented Apr 4, 2016 at 8:48
  • 1
    Your current approach isn't all bad and the only way to have full control on everything. Commented Apr 4, 2016 at 8:49

4 Answers 4

19

I would avoid reflection if possible.

You can achieve it with compile time safety and readable code easily:

IEnumerable<string> personTexts = listOfPersons
    .Select(p => String.Join(",", p.ReferenceNumber, p.FirstName, p.Surname, ...));
string joined = String.Join(Environment.NewLine, personTexts);

You have full control over which property should be used and in which order.

Sign up to request clarification or add additional context in comments.

Comments

7

Reflection is (sometimes) your friend:

var props = item.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); // todo: cache & filter not-needed props)

var itemStr = string.Join(", ", 
                     props.Select(p => p.GetValue(item, null)?.ToString())
                          .ToArray());

1 Comment

Reflection totally helped. Thanks! :) @nopeflow
4

Overrride the ToString-Method for your Person-Class

public class Person
{
    //properties...

    public override string ToString()
    {
        return string.Join(",",
            this.ReferenceNumber,
            this.FirstName,
            this.Surname,
            this.MiddleName,
            this.Address1,
            this.Address2,
            this.Address3,
            this.Address4,
            this.City,
            this.PostalCode,
            this.Country,
            this.DateOfBirth.ToString(),
            this.ID,
            this.Gender,
            this.Component,
            this.NationalID,
            this.SubSystemID,
            this.System);
    }
}

so you can use Person.ToString() for csv-generation. Unlike the reflection approach you can easy

  • maintain the order
  • handle each type different (BirthDate.ToString("d"), Price.ToString("F2"))
  • skip values you don't need e.g. System.Collections.Generic.List1[System.String]
  • change values to your requirements (HasChildren ? "Yes" : "No")

Comments

0

Using Reflection where T : class

var valueLines =reportData.Select(row => string.Join(",", header.Split(',').Select(a => row.GetType().GetProperty(a).GetValue(row, null))));

eg

private MemoryStream GenerateExcelStream(List<T> reportData)
    {
        var lines = new List<string>();
        var header = "";
        var attFilter = new NoDisplayInReportAttribute();
        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
        foreach (PropertyDescriptor prop in properties)
            if (!prop.Attributes.Matches(attFilter))
                header += prop.Name + ",";
        header = header.Substring(0, header.Length - 1);
        lines.Add(header);
        var valueLines =reportData.Select(row => string.Join(",", header.Split(',').Select(a => row.GetType().GetProperty(a).GetValue(row, null))));
        lines.AddRange(valueLines);
        MemoryStream memoryStream = new MemoryStream();
        TextWriter tw = new StreamWriter(memoryStream);
        lines.ForEach(x => tw.WriteLine(x));
        tw.Flush();
        return memoryStream;
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.