2016-11-25 3 views
1

Ich bin ein Anfänger mit YAML und studiere, wie man YAML in C# parst. Hier versuche ich, C# -Objektmodule zu analysieren, wo ich Daten von komplexen Objekttypen wie DataTable-Klasse oder Type-Klasse in C# habe. Ich weiß, wie man grundlegende Arten unter Verwendung der YAMLDotNet Bibliothek umwandelt, aber weiß wirklich nicht, wie man mit solchen Typen das Gleiche tut. Bitte helfen.Komplexe Typen von C# in YAML konvertieren

Antwort

0

Ein DataTable ist ein komplexes Objekt mit verlorenen Eigenschaften. Der einfachste Weg wäre, die für Sie relevanten Daten in eine einfachere Datenstruktur zu extrahieren und stattdessen zu serialisieren. Sie können jedoch eine benutzerdefinierte IYamlTypeConverter erstellen, wenn Sie wirklich möchten. Hier ist ein Beispiel, das die Tabellenspaltennamen und Typen sowie die Werte der Zeilen wird serialisiert:

public class DataTableTypeConverter : IYamlTypeConverter 
{ 
    public bool Accepts(Type type) 
    { 
     return typeof(DataTable).IsAssignableFrom(type); 
    } 

    public object ReadYaml(IParser parser, Type type) 
    { 
     var table = new DataTable(); 

     parser.Expect<MappingStart>(); 

     ReadColumns(parser, table); 
     ReadRows(parser, table); 

     parser.Expect<MappingEnd>(); 

     return table; 
    } 

    private static void ReadColumns(IParser parser, DataTable table) 
    { 
     var columns = parser.Expect<Scalar>(); 
     if (columns.Value != "columns") 
     { 
      throw new YamlException(columns.Start, columns.End, 
            "Expected a scalar named 'columns'"); 
     } 

     parser.Expect<MappingStart>(); 
     while (parser.Allow<MappingEnd>() == null) 
     { 
      var columnName = parser.Expect<Scalar>(); 
      var typeName = parser.Expect<Scalar>(); 

      table.Columns.Add(columnName.Value, Type.GetType(typeName.Value)); 
     } 
    } 

    private static void ReadRows(IParser parser, DataTable table) 
    { 
     var columns = parser.Expect<Scalar>(); 
     if (columns.Value != "rows") 
     { 
      throw new YamlException(columns.Start, columns.End, 
            "Expected a scalar named 'rows'"); 
     } 

     parser.Expect<SequenceStart>(); 
     while (parser.Allow<SequenceEnd>() == null) 
     { 
      var row = table.NewRow(); 

      var columnIndex = 0; 
      parser.Expect<SequenceStart>(); 
      while (parser.Allow<SequenceEnd>() == null) 
      { 
       var value = parser.Expect<Scalar>(); 
       var columnType = table.Columns[columnIndex].DataType; 
       row[columnIndex] = TypeConverter.ChangeType(value.Value, columnType); 
       ++columnIndex; 
      } 

      table.Rows.Add(row); 
     } 
    } 

    public void WriteYaml(IEmitter emitter, object value, Type type) 
    { 
     var table = (DataTable)value; 
     emitter.Emit(new MappingStart()); 

     EmitColumns(emitter, table); 
     EmitRows(emitter, table); 

     emitter.Emit(new MappingEnd()); 
    } 

    private static void EmitColumns(IEmitter emitter, DataTable table) 
    { 
     emitter.Emit(new Scalar("columns")); 
     emitter.Emit(new MappingStart(null, null, true, MappingStyle.Block)); 
     foreach (DataColumn column in table.Columns) 
     { 
      emitter.Emit(new Scalar(column.ColumnName)); 
      emitter.Emit(new Scalar(column.DataType.AssemblyQualifiedName)); 
     } 
     emitter.Emit(new MappingEnd()); 
    } 

    private static void EmitRows(IEmitter emitter, DataTable table) 
    { 
     emitter.Emit(new Scalar("rows")); 
     emitter.Emit(new SequenceStart(null, null, true, SequenceStyle.Block)); 

     foreach (DataRow row in table.Rows) 
     { 
      emitter.Emit(new SequenceStart(null, null, true, SequenceStyle.Flow)); 
      foreach (var item in row.ItemArray) 
      { 
       var value = TypeConverter.ChangeType<string>(item); 
       emitter.Emit(new Scalar(value)); 
      } 
      emitter.Emit(new SequenceEnd()); 
     } 

     emitter.Emit(new SequenceEnd()); 
    } 
} 

Es wird wie folgt verwendet:

var table = new DataTable(); 
table.Columns.Add("id", typeof(int)); 
table.Columns.Add("name", typeof(string)); 
table.Columns.Add("description", typeof(string)); 

table.Rows.Add(1, "first", "The first row"); 
table.Rows.Add(2, "second", "The second row"); 

// Serialize 
var serializer = new SerializerBuilder() 
    .WithTypeConverter(new DataTableTypeConverter()) 
    .Build(); 

var yaml = serializer.Serialize(table); 

// Deserialize 
var deserializer = new DeserializerBuilder() 
    .WithTypeConverter(new DataTableTypeConverter()) 
    .Build(); 

var parsedTable = deserializer.Deserialize<DataTable>(yaml); 

Die serialisierten YAML ist in diesem Beispiel :

columns: 
    id: System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
    name: System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
    description: System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
rows: 
- [1, first, The first row] 
- [2, second, The second row] 
+0

Danke :) Es hat funktioniert (y) – Anonymous