2012-06-15 12 views
15

¿Cómo puedo escribir todos los valores (propiedades) en una cadena formateada csv en C#? por ejemplo:Entidad objeto a serialización/conversión CSV

class Person(string firstName, string lastName, int_age); 
Person person = new Person("Kevin","Kline",33); 

ahora quiero una cadena "Kevin; Kline; 33"

En otras palabras, quiero serializar un objeto en CSV

+4

valores de qué? –

+0

Su pregunta necesita más antecedentes y ejemplos de datos/códigos para evitar ser un candidato para el cierre. –

+1

¿Puede mostrarnos lo que ya ha intentado? – LolCat

Respuesta

2

se puede usar algo como esto:

... 
     PropertyInfo[] properties = obj.GetType().GetProperties(); 
     string CSVRow = ""; 
     foreach (PropertyInfo pi in properties) 
     { 
      CSVRow = CSVRow + pi.GetValue(obj, null) + ";"; 
     } 
     CSVRow.Remove(CSVRow.Length - 1, 1); 
... 
+3

... pero también necesitaría implementar reglas de cita/escape. – Joe

0

Algo como esto:

public string ToCsv() 
{ 
    return string.Join(";", new string[]{ 
     _firstName, 
     _lastName, 
     _age.ToString() 
    }.Select(str=>Escape(str))); 
} 

O, utilizando la reflexión,

public static string ToCsv(this object obj) 
{ 
    return string.Join(";", 
     this.GetType().GetProperties().Select(pi=> 
      Escape(pi.GetValue(this, null).ToString()) 
     )); 
} 

donde la salida es una función de escape apropiado.

9

Mediante el uso de la reflexión puede recuperar las informaciones de propiedad de un objeto

foreach (PropertyInfo prp in obj.GetType().GetProperties()) { 
    if (prp.CanRead) { 
     object value = prp.GetValue(obj, null); 
     string s = value == null ? "" : value.ToString(); 
     string name = prp.Name; 
     ... 
    } 
} 

El método GetProperties tiene una sobrecarga aceptar BindingFlags a través del cual se puede determinar qué tipo de propiedad que necesita, como privada instancia/public/estática .

Puedes combinarlos como esto

var properties = type.GetProperties(BindingFlags.Public | 
            BindingFlags.NonPublic | 
            BindingFlags.Instance); 

Aplicado a su problema podría escribir

List<Person> people = ...; 
Type type = typeof(Person); 
PropertyInfo[] properties = type.GetProperties(); 
var sb = new StringBuilder(); 

// First line contains field names 
foreach (PropertyInfo prp in properties) { 
    if (prp.CanRead) { 
     sb.Append(prp.Name).Append(';'); 
    } 
} 
sb.Length--; // Remove last ";" 
sb.AppendLine(); 

foreach (Person person in people) { 
    foreach (PropertyInfo prp in properties) { 
     if (prp.CanRead) { 
      sb.Append(prp.GetValue(person, null)).Append(';'); 
     } 
    } 
    sb.Length--; // Remove last ";" 
    sb.AppendLine(); 
} 

File.AppendAllText("C:\Data\Persons.csv", sb.ToString()); 

También es una buena idea para encerrar las cadenas entre comillas dobles y para escapar de dobles citas que contienen al doblarlas.

13

Tenga una mirada en Josh Close's excelente CSVHelper biblioteca

var person = new Person("Kevin","Kline",33); 
using (var csv = new CsvWriter(new StreamWriter("file.csv"))) 
{ 
    csv.Configuration.HasHeaderRecord = false; 
    csv.Configuration.Delimiter = ';'; 
    csv.WriteRecord(person); 
} 

Salida:

Kevin;Kline;33 
+0

¿Es posible usar CSVHelper, sin la parte guardada file.csv? No quiero escribir el archivo en el HD, tengo la intención de enviar el archivo como una respuesta al usuario web. – Lombas

+4

La mejor parte es que está disponible para .Net Core –

2

Creo FileHelpers es bueno para esto, he no lo usaron en la ira a mí mismo, aunque

+0

Es bueno. Lástima que no funciona para .Net Core:/¡CSVHelper sí! –

0

Una implementación posible para usted, que lee objetos complejos (serialización profunda de objetos), como una matriz de objetos con propiedades que son ay de objetos, y guarda o una cadena formateada como archivo CSV:

private string ToCsv(string separator, IEnumerable<object> objectList) 
{ 
    StringBuilder csvData = new StringBuilder(); 
    foreach (var obj in objectList) 
    { 
     csvData.AppendLine(ToCsvFields(separator, obj)); 
    } 
    return csvData.ToString(); 
} 

private string ToCsvFields(string separator, object obj) 
{ 
    var fields = obj.GetType().GetProperties(); 
    StringBuilder line = new StringBuilder(); 

    if (obj is string) 
    { 
     line.Append(obj as string); 
     return line.ToString(); 
    } 

    foreach (var field in fields) 
    { 
     var value = field.GetValue(obj); 
     var fieldType = field.GetValue(obj).GetType(); 

     if (line.Length > 0) 
     { 
      line.Append(separator); 
     } 
     if (value == null) 
     { 
      line.Append("NULL"); 
     } 
     if (value is string) 
     { 
      line.Append(value as string); 
     } 
     if (typeof(IEnumerable).IsAssignableFrom(fieldType)) 
     { 
      var objectList = value as IEnumerable; 
      StringBuilder row = new StringBuilder(); 

      foreach (var item in objectList) 
      { 
       if (row.Length > 0) 
       { 
        row.Append(separator); 
       } 
       row.Append(ToCsvFields(separator, item)); 
      } 
      line.Append(row.ToString()); 
     } 
     else 
     { 
      line.Append(value.ToString()); 
     } 
    } 
    return line.ToString(); 
}