Question

I have data in the following structure:

Structure student
    Dim stdntpass As String
    Dim fname As String
    Dim sname As String
    Dim age As Byte
    Dim year As Integer
    Dim stdntuser As String
End Structure

I need to take the data in that structure and output it to CSV. I was planning on using a StringBuilder object to do it, but I can't figure out how to give the structure to the StringBuilder.

Was it helpful?

Solution

Here is a function that uses reflection to determine what fields exist in the student structure:

Public Function StudentsToCSV(students As IEnumerable(Of student)) As String
    Const separator As Char = ";"c
    Dim sb As New StringBuilder

    'Get the data elements
    Dim studentFields = GetType(student).GetFields()

    'Output headline (may be removed)
    For Each field In studentFields
        sb.Append(field.Name)
        sb.Append(separator)
    Next
    sb.AppendLine("")

    'Write a line for each student
    For Each s In students
        'Write the value of each field
        For Each field In studentFields
            Dim value As String = Convert.ToString(field.GetValue(s))
            sb.Append(value)
            '... followed by the separator
            sb.Append(separator)
        Next
        sb.AppendLine("")
    Next
    Return sb.ToString()
End Function

You can pass any set of students to this function - may it be an array, a List(Of student) or whatever.

OTHER TIPS

One way is to override the ToString function. now passing a whole object to a stringbuilder or even sending the Tostring function to the file will pass the values how you want them:

Structure student
    Dim stdntpass As String
    Dim fname As String
    Dim sname As String
    Dim age As Byte
    Dim year As Integer
    Dim stdntuser As String
    Public Overrides Function ToString() As String
        Return Join({stdntpass, fname, sname, age.ToString, year.ToString, stdntuser}, ","c) + vbNewLine
    End Function
End Structure

The StringBuilder has no way to take a whole Structure and automatically append each of the properties from that Structure. If you must use a StringBuilder, you could do it like this:

builder.Append(s.stdntpass)
builder.Append(",")
builder.Append(s.fname)
builder.Append(",")
builder.Append(s.sname)
builder.Append(",")
builder.Append(s.age)
builder.Append(",")
builder.Append(s.year)
builder.Append(",")
builder.Append(s.stdntuser)
Dim csvLine As String = builder.ToString()

However, it would be easier to use the String.Join method, like this:

Dim csvLine As String = String.Join(",", s.stdntpass, s.fname, s.sname, s.age, s.year, s.stdntuser)

You could use reflection to dynamically get the list of properties from the structure, but then you won't have much control over the order in which the fields get appended without using attributes, or something, which could get ugly.

In any case, you should be careful, though, that values are properly escaped. If any of the strings in your structure contain commas, you need to surround that field with quotation marks. And if any of those strings quotation marks, they need to be doubled. You could fix the values with a method like this:

Public Function EscapeValueForCsv(value As String) As String
    Return """" & value.Replace("""", """""") & """"
End Function

Then you could call that on each of the properties before passing it to String.Join:

Dim csvLine As String = String.Join _
    (
    ",", 
    EscapeValueForCsv(s.stdntpass), 
    EscapeValueForCsv(s.fname), 
    EscapeValueForCsv(s.sname), 
    EscapeValueForCsv(s.age.ToString()),
    EscapeValueForCsv(s.year.ToString()), 
    EscapeValueForCsv(s.stdntuser)
    )
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top