将 C# 的复杂类型转换为 YAML
Converting Complex types of C# into YAML
我是 YAML 的初学者,正在研究如何将 YAML 解析为 C#。在这里,我试图解析 C# 对象模块,其中我有复杂对象类型的数据,例如 C# 中的 DataTable class 或 Type class 。
我知道如何使用 YAMLDotNet 库转换基本类型,但真的不知道如何对这些类型做同样的事情。
请帮忙。
A DataTable
是一个失去属性的复杂对象。最简单的方法是将与您相关的数据提取到更简单的数据结构中,然后将其序列化。但是,如果您真的愿意,可以创建自定义 IYamlTypeConverter
。下面是一个示例,它将序列化 table 的列名和类型,以及行的值:
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]
我是 YAML 的初学者,正在研究如何将 YAML 解析为 C#。在这里,我试图解析 C# 对象模块,其中我有复杂对象类型的数据,例如 C# 中的 DataTable class 或 Type class 。 我知道如何使用 YAMLDotNet 库转换基本类型,但真的不知道如何对这些类型做同样的事情。 请帮忙。
A DataTable
是一个失去属性的复杂对象。最简单的方法是将与您相关的数据提取到更简单的数据结构中,然后将其序列化。但是,如果您真的愿意,可以创建自定义 IYamlTypeConverter
。下面是一个示例,它将序列化 table 的列名和类型,以及行的值:
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]