2 votes

Convertir des types complexes de C# en YAML

Je suis un débutant avec YAML et j'étudie comment analyser YAML en C#. Ici, j'essaie d'analyser les modules d'objets C# où j'ai des données de types d'objets complexes tels que la classe DataTable ou la classe Type en C#. Je sais comment convertir des types de base en utilisant la bibliothèque YAMLDotNet mais je ne sais vraiment pas comment faire la même chose avec de tels types. Veuillez m'aider.

1voto

Antoine Aubry Points 3276

A DataTable est un objet complexe avec une multitude de propriétés. Le plus simple serait d'extraire les données qui vous intéressent dans une structure de données plus simple et de la sérialiser. Cependant, vous pouvez créer un IYamlTypeConverter si tu le veux vraiment. Voici un exemple qui sérialise les noms et le type des colonnes de la table, ainsi que les valeurs des lignes :

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());
    }
}

Il est utilisé comme suit :

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);

Le YAML sérialisé dans cet exemple est :

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]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X