【问题标题】:Converting Complex types of C# into YAML将复杂类型的 C# 转换为 YAML
【发布时间】:2016-11-25 06:26:35
【问题描述】:

我是 YAML 的初学者,正在研究如何将 YAML 解析为 C#。在这里,我试图解析 C# 对象模块,其中我有复杂对象类型的数据,例如 C# 中的 DataTable 类或 Type 类。 我知道如何使用 YAMLDotNet 库转换基本类型,但真的不知道如何对这些类型做同样的事情。 请帮忙。

【问题讨论】:

    标签: c# serialization deserialization yaml yamldotnet


    【解决方案1】:

    DataTable 是一个失去属性的复杂对象。最简单的方法是将与您相关的数据提取到更简单的数据结构中,然后将其序列化。但是,如果您真的愿意,您可以创建自定义 IYamlTypeConverter。下面是一个示例,它将序列化表的列名和类型,以及行的值:

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

    用法如下:

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

    本例中的序列化 YAML 为:

    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]
    

    【讨论】:

    • IYamlTypeConverter 是否记录在任何地方?使用这个答案,我能够破解我的问题来解决我的问题。
    猜你喜欢
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-29
    • 1970-01-01
    相关资源
    最近更新 更多