зеркало из https://github.com/stride3d/SharpYaml.git
Implement more of the deserializer.
This commit is contained in:
Родитель
a7b83ea9fb
Коммит
56e58bed1d
|
@ -13,7 +13,7 @@
|
|||
<tags>yaml parser development library</tags>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\YamlDotNet.Core\bin\Release\YamlDotNet.Core.dll" target="lib" />
|
||||
<file src="..\YamlDotNet.Core\bin\Release\YamlDotNet.Core.pdb" target="lib" />
|
||||
<file src="..\YamlDotNet.Core\bin\Release\YamlDotNet.Core.dll" target="lib\net35" />
|
||||
<file src="..\YamlDotNet.Core\bin\Release\YamlDotNet.Core.pdb" target="lib\net35" />
|
||||
</files>
|
||||
</package>
|
|
@ -78,20 +78,47 @@ namespace YamlDotNet.RepresentationModel.Serialization
|
|||
/// </summary>
|
||||
public class Deserializer
|
||||
{
|
||||
private readonly ICollection<INodeDeserializer> _deserializers;
|
||||
private readonly IEnumerable<INodeDeserializer> _deserializers;
|
||||
private readonly IEnumerable<INodeTypeResolver> _typeResolvers;
|
||||
|
||||
public Deserializer()
|
||||
{
|
||||
// TODO: Allow to override the object factory
|
||||
var objectFactory = new DefaultObjectFactory();
|
||||
|
||||
_deserializers = new INodeDeserializer[]
|
||||
{
|
||||
new NullNodeDeserializer(),
|
||||
new ScalarNodeDeserializer(),
|
||||
new GenericDictionaryDeserializer(objectFactory),
|
||||
new NonGenericDictionaryDeserializer(objectFactory),
|
||||
new GenericCollectionDeserializer(objectFactory),
|
||||
new NonGenericListDeserializer(objectFactory),
|
||||
new EnumerableDeserializer(),
|
||||
new ObjectNodeDeserializer(objectFactory),
|
||||
};
|
||||
|
||||
_typeResolvers = new INodeTypeResolver[]
|
||||
{
|
||||
new PredefinedTagsNodeTypeResolver(),
|
||||
new TypeNameInTagNodeTypeResolver(),
|
||||
new DefaultContainersNodeTypeResolver(),
|
||||
};
|
||||
}
|
||||
|
||||
public object Deserialize(TextReader input, Type type)
|
||||
public object Deserialize(TextReader input, DeserializationFlags options = DeserializationFlags.None)
|
||||
{
|
||||
return Deserialize(new EventReader(new Parser(input)), type);
|
||||
return Deserialize(input, typeof(object), options);
|
||||
}
|
||||
|
||||
public object Deserialize(TextReader input, Type type, DeserializationFlags options = DeserializationFlags.None)
|
||||
{
|
||||
return Deserialize(new EventReader(new Parser(input)), type, options);
|
||||
}
|
||||
|
||||
public object Deserialize(EventReader reader, DeserializationFlags options = DeserializationFlags.None)
|
||||
{
|
||||
return Deserialize(reader, typeof(object), options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -136,12 +163,12 @@ namespace YamlDotNet.RepresentationModel.Serialization
|
|||
{
|
||||
var nodeEvent = reader.Peek<NodeEvent>();
|
||||
|
||||
var nodeType = GetTypeFromTag(nodeEvent.Tag, expectedType);
|
||||
var nodeType = GetTypeFromEvent(nodeEvent, expectedType);
|
||||
|
||||
foreach (var deserializer in _deserializers)
|
||||
{
|
||||
object value;
|
||||
if (deserializer.Deserialize(reader, nodeType, out value))
|
||||
if (deserializer.Deserialize(reader, nodeType, (r, t) => DeserializeValue(r, t, context), out value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
@ -189,6 +216,36 @@ namespace YamlDotNet.RepresentationModel.Serialization
|
|||
// return false;
|
||||
//}
|
||||
|
||||
|
||||
private Type GetTypeFromEvent(NodeEvent nodeEvent, Type currentType)//, TagMappings mappings)
|
||||
{
|
||||
foreach (var typeResolver in _typeResolvers)
|
||||
{
|
||||
if (typeResolver.Resolve(nodeEvent, ref currentType))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return currentType;
|
||||
}
|
||||
}
|
||||
|
||||
public interface INodeTypeResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines the type of the specified node.
|
||||
/// </summary>
|
||||
/// <param name="nodeEvent">The node to be deserialized.</param>
|
||||
/// <param name="currentType">The type that has been determined so far.</param>
|
||||
/// <returns>
|
||||
/// true if <paramref name="currentType"/> has been resolved completely;
|
||||
/// false if the next type <see cref="INodeTypeResolver"/> should be invoked.
|
||||
/// </returns>
|
||||
bool Resolve(NodeEvent nodeEvent, ref Type currentType);
|
||||
}
|
||||
|
||||
public sealed class PredefinedTagsNodeTypeResolver : INodeTypeResolver
|
||||
{
|
||||
private static readonly Dictionary<string, Type> predefinedTypes = new Dictionary<string, Type>
|
||||
{
|
||||
{ "tag:yaml.org,2002:map", typeof(Dictionary<object, object>) },
|
||||
|
@ -199,31 +256,61 @@ namespace YamlDotNet.RepresentationModel.Serialization
|
|||
{ "tag:yaml.org,2002:timestamp", typeof(DateTime) },
|
||||
};
|
||||
|
||||
private static Type GetTypeFromTag(string tag, Type defaultType)//, TagMappings mappings)
|
||||
bool INodeTypeResolver.Resolve(NodeEvent nodeEvent, ref Type currentType)
|
||||
{
|
||||
if (tag == null)
|
||||
Type predefinedType;
|
||||
if (!string.IsNullOrEmpty(nodeEvent.Tag) && predefinedTypes.TryGetValue(nodeEvent.Tag, out predefinedType))
|
||||
{
|
||||
return defaultType;
|
||||
currentType = predefinedType;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DefaultContainersNodeTypeResolver : INodeTypeResolver
|
||||
{
|
||||
bool INodeTypeResolver.Resolve(NodeEvent nodeEvent, ref Type currentType)
|
||||
{
|
||||
if (currentType == typeof(object))
|
||||
{
|
||||
if (nodeEvent is SequenceStart)
|
||||
{
|
||||
currentType = typeof(List<object>);
|
||||
return true;
|
||||
}
|
||||
if (nodeEvent is MappingStart)
|
||||
{
|
||||
currentType = typeof(Dictionary<object, object>);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//Type predefinedType = mappings.GetMapping(tag);
|
||||
//if (predefinedType != null || predefinedTypes.TryGetValue(tag, out predefinedType))
|
||||
//{
|
||||
// return predefinedType;
|
||||
//}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return Type.GetType(tag.Substring(1), true);
|
||||
public sealed class TypeNameInTagNodeTypeResolver : INodeTypeResolver
|
||||
{
|
||||
bool INodeTypeResolver.Resolve(NodeEvent nodeEvent, ref Type currentType)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(nodeEvent.Tag))
|
||||
{
|
||||
currentType = Type.GetType(nodeEvent.Tag.Substring(1), true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public interface INodeDeserializer
|
||||
{
|
||||
bool Deserialize(EventReader reader, Type expectedType, out object value);
|
||||
bool Deserialize(EventReader reader, Type expectedType, Func<EventReader, Type, object> nestedObjectDeserializer, out object value);
|
||||
}
|
||||
|
||||
public sealed class NullNodeDeserializer : INodeDeserializer
|
||||
{
|
||||
bool INodeDeserializer.Deserialize(EventReader reader, Type expectedType, out object value)
|
||||
bool INodeDeserializer.Deserialize(EventReader reader, Type expectedType, Func<EventReader, Type, object> nestedObjectDeserializer, out object value)
|
||||
{
|
||||
value = null;
|
||||
var evt = reader.Peek<NodeEvent>();
|
||||
|
@ -240,7 +327,7 @@ namespace YamlDotNet.RepresentationModel.Serialization
|
|||
|
||||
public sealed class JsonNullNodeDeserializer : INodeDeserializer
|
||||
{
|
||||
bool INodeDeserializer.Deserialize(EventReader reader, Type expectedType, out object value)
|
||||
bool INodeDeserializer.Deserialize(EventReader reader, Type expectedType, Func<EventReader, Type, object> nestedObjectDeserializer, out object value)
|
||||
{
|
||||
value = null;
|
||||
var scalar = reader.Peek<Scalar>();
|
||||
|
@ -258,7 +345,7 @@ namespace YamlDotNet.RepresentationModel.Serialization
|
|||
|
||||
public sealed class ScalarNodeDeserializer : INodeDeserializer
|
||||
{
|
||||
bool INodeDeserializer.Deserialize(EventReader reader, Type expectedType, out object value)
|
||||
bool INodeDeserializer.Deserialize(EventReader reader, Type expectedType, Func<EventReader, Type, object> nestedObjectDeserializer, out object value)
|
||||
{
|
||||
var scalar = reader.Allow<Scalar>();
|
||||
if (scalar == null)
|
||||
|
@ -374,4 +461,220 @@ namespace YamlDotNet.RepresentationModel.Serialization
|
|||
NumberDecimalDigits = 99
|
||||
};
|
||||
}
|
||||
|
||||
public sealed class ObjectNodeDeserializer : INodeDeserializer
|
||||
{
|
||||
private readonly IObjectFactory _objectFactory;
|
||||
|
||||
public ObjectNodeDeserializer(IObjectFactory objectFactory)
|
||||
{
|
||||
_objectFactory = objectFactory;
|
||||
}
|
||||
|
||||
bool INodeDeserializer.Deserialize(EventReader reader, Type expectedType, Func<EventReader, Type, object> nestedObjectDeserializer, out object value)
|
||||
{
|
||||
var mapping = reader.Allow<MappingStart>();
|
||||
if (mapping == null)
|
||||
{
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
value = _objectFactory.Create(expectedType);
|
||||
while (!reader.Accept<MappingEnd>())
|
||||
{
|
||||
var propertyName = reader.Expect<Scalar>();
|
||||
|
||||
// TODO: Find property according to naming conventions
|
||||
var property = expectedType.GetProperty(propertyName.Value, BindingFlags.Instance | BindingFlags.Public);
|
||||
var propertyValue = nestedObjectDeserializer(reader, property.PropertyType);
|
||||
property.SetValue(value, propertyValue, null);
|
||||
}
|
||||
|
||||
reader.Expect<MappingEnd>();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class GenericDictionaryDeserializer : INodeDeserializer
|
||||
{
|
||||
private readonly IObjectFactory _objectFactory;
|
||||
|
||||
public GenericDictionaryDeserializer(IObjectFactory objectFactory)
|
||||
{
|
||||
_objectFactory = objectFactory;
|
||||
}
|
||||
|
||||
bool INodeDeserializer.Deserialize(EventReader reader, Type expectedType, Func<EventReader, Type, object> nestedObjectDeserializer, out object value)
|
||||
{
|
||||
var iDictionary = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(IDictionary<,>));
|
||||
if (iDictionary == null)
|
||||
{
|
||||
value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
reader.Expect<MappingStart>();
|
||||
|
||||
value = _objectFactory.Create(expectedType);
|
||||
_deserializeHelperMethod
|
||||
.MakeGenericMethod(iDictionary.GetGenericArguments())
|
||||
.Invoke(null, new object[] { reader, expectedType, nestedObjectDeserializer, value });
|
||||
|
||||
reader.Expect<MappingEnd>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static MethodInfo _deserializeHelperMethod = typeof(GenericDictionaryDeserializer)
|
||||
.GetMethod("DeserializeHelper", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
|
||||
private static void DeserializeHelper<TKey, TValue>(EventReader reader, Type expectedType, Func<EventReader, Type, object> nestedObjectDeserializer, IDictionary<TKey, TValue> result)
|
||||
{
|
||||
while (!reader.Accept<MappingEnd>())
|
||||
{
|
||||
var key = (TKey)nestedObjectDeserializer(reader, typeof(TKey));
|
||||
var value = (TValue)nestedObjectDeserializer(reader, typeof(TValue));
|
||||
result.Add(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class NonGenericDictionaryDeserializer : INodeDeserializer
|
||||
{
|
||||
private readonly IObjectFactory _objectFactory;
|
||||
|
||||
public NonGenericDictionaryDeserializer(IObjectFactory objectFactory)
|
||||
{
|
||||
_objectFactory = objectFactory;
|
||||
}
|
||||
|
||||
bool INodeDeserializer.Deserialize(EventReader reader, Type expectedType, Func<EventReader, Type, object> nestedObjectDeserializer, out object value)
|
||||
{
|
||||
if(!typeof(IDictionary).IsAssignableFrom(expectedType))
|
||||
{
|
||||
value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
reader.Expect<MappingStart>();
|
||||
|
||||
var dictionary = (IDictionary)_objectFactory.Create(expectedType);
|
||||
while (!reader.Accept<MappingEnd>())
|
||||
{
|
||||
var key = nestedObjectDeserializer(reader, typeof(object));
|
||||
var keyValue = nestedObjectDeserializer(reader, typeof(object));
|
||||
dictionary.Add(key, keyValue);
|
||||
}
|
||||
value = dictionary;
|
||||
|
||||
reader.Expect<MappingEnd>();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class GenericCollectionDeserializer : INodeDeserializer
|
||||
{
|
||||
private readonly IObjectFactory _objectFactory;
|
||||
|
||||
public GenericCollectionDeserializer(IObjectFactory objectFactory)
|
||||
{
|
||||
_objectFactory = objectFactory;
|
||||
}
|
||||
|
||||
bool INodeDeserializer.Deserialize(EventReader reader, Type expectedType, Func<EventReader, Type, object> nestedObjectDeserializer, out object value)
|
||||
{
|
||||
var iCollection = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(ICollection<>));
|
||||
if (iCollection == null)
|
||||
{
|
||||
value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
reader.Expect<SequenceStart>();
|
||||
|
||||
value = _objectFactory.Create(expectedType);
|
||||
_deserializeHelperMethod
|
||||
.MakeGenericMethod(iCollection.GetGenericArguments())
|
||||
.Invoke(null, new object[] { reader, expectedType, nestedObjectDeserializer, value });
|
||||
|
||||
reader.Expect<SequenceEnd>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static MethodInfo _deserializeHelperMethod = typeof(GenericCollectionDeserializer)
|
||||
.GetMethod("DeserializeHelper", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
|
||||
private static void DeserializeHelper<TItem>(EventReader reader, Type expectedType, Func<EventReader, Type, object> nestedObjectDeserializer, ICollection<TItem> result)
|
||||
{
|
||||
while (!reader.Accept<SequenceEnd>())
|
||||
{
|
||||
var value = (TItem)nestedObjectDeserializer(reader, typeof(TItem));
|
||||
result.Add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class NonGenericListDeserializer : INodeDeserializer
|
||||
{
|
||||
private readonly IObjectFactory _objectFactory;
|
||||
|
||||
public NonGenericListDeserializer(IObjectFactory objectFactory)
|
||||
{
|
||||
_objectFactory = objectFactory;
|
||||
}
|
||||
|
||||
bool INodeDeserializer.Deserialize(EventReader reader, Type expectedType, Func<EventReader, Type, object> nestedObjectDeserializer, out object value)
|
||||
{
|
||||
if (!typeof(IList).IsAssignableFrom(expectedType))
|
||||
{
|
||||
value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
reader.Expect<SequenceStart>();
|
||||
|
||||
var list = (IList)_objectFactory.Create(expectedType);
|
||||
while (!reader.Accept<SequenceEnd>())
|
||||
{
|
||||
var item = nestedObjectDeserializer(reader, typeof(object));
|
||||
list.Add(item);
|
||||
}
|
||||
value = list;
|
||||
|
||||
reader.Expect<SequenceEnd>();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class EnumerableDeserializer : INodeDeserializer
|
||||
{
|
||||
bool INodeDeserializer.Deserialize(EventReader reader, Type expectedType, Func<EventReader, Type, object> nestedObjectDeserializer, out object value)
|
||||
{
|
||||
Type itemsType;
|
||||
if (expectedType == typeof(IEnumerable))
|
||||
{
|
||||
itemsType = typeof(object);
|
||||
}
|
||||
else
|
||||
{
|
||||
var iEnumerable = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(IEnumerable<>));
|
||||
if (iEnumerable != expectedType)
|
||||
{
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
itemsType = iEnumerable.GetGenericArguments()[0];
|
||||
}
|
||||
|
||||
var collectionType = typeof(List<>).MakeGenericType(itemsType);
|
||||
value = nestedObjectDeserializer(reader, collectionType);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -310,7 +310,7 @@ namespace YamlDotNet.UnitTests.RepresentationModel
|
|||
[Fact]
|
||||
public void DeserializeDictionary()
|
||||
{
|
||||
YamlSerializer serializer = new YamlSerializer();
|
||||
var serializer = new Deserializer();
|
||||
object result = serializer.Deserialize(YamlFile("dictionary.yaml"));
|
||||
|
||||
Assert.True(typeof(IDictionary<object, object>).IsAssignableFrom(result.GetType()), "The deserialized object has the wrong type.");
|
||||
|
@ -323,7 +323,7 @@ namespace YamlDotNet.UnitTests.RepresentationModel
|
|||
[Fact]
|
||||
public void DeserializeExplicitDictionary()
|
||||
{
|
||||
YamlSerializer serializer = new YamlSerializer();
|
||||
var serializer = new Deserializer();
|
||||
object result = serializer.Deserialize(YamlFile("dictionaryExplicit.yaml"));
|
||||
|
||||
Assert.True(typeof(IDictionary<string, int>).IsAssignableFrom(result.GetType()), "The deserialized object has the wrong type.");
|
||||
|
@ -336,8 +336,8 @@ namespace YamlDotNet.UnitTests.RepresentationModel
|
|||
[Fact]
|
||||
public void DeserializeListOfDictionaries()
|
||||
{
|
||||
var serializer = new YamlSerializer<List<Dictionary<string, string>>>();
|
||||
object result = serializer.Deserialize(YamlFile("listOfDictionaries.yaml"));
|
||||
var serializer = new Deserializer();
|
||||
object result = serializer.Deserialize(YamlFile("listOfDictionaries.yaml"), typeof(List<Dictionary<string, string>>));
|
||||
|
||||
Assert.IsType<List<Dictionary<string, string>>>(result);
|
||||
|
||||
|
@ -351,7 +351,7 @@ namespace YamlDotNet.UnitTests.RepresentationModel
|
|||
[Fact]
|
||||
public void DeserializeList()
|
||||
{
|
||||
YamlSerializer serializer = new YamlSerializer();
|
||||
var serializer = new Deserializer();
|
||||
object result = serializer.Deserialize(YamlFile("list.yaml"));
|
||||
|
||||
Assert.True(typeof(IList).IsAssignableFrom(result.GetType()));
|
||||
|
@ -365,7 +365,7 @@ namespace YamlDotNet.UnitTests.RepresentationModel
|
|||
[Fact]
|
||||
public void DeserializeExplicitList()
|
||||
{
|
||||
YamlSerializer serializer = new YamlSerializer();
|
||||
var serializer = new Deserializer();
|
||||
object result = serializer.Deserialize(YamlFile("listExplicit.yaml"));
|
||||
|
||||
Assert.True(typeof(IList<int>).IsAssignableFrom(result.GetType()));
|
||||
|
@ -384,8 +384,8 @@ namespace YamlDotNet.UnitTests.RepresentationModel
|
|||
StringWriter buffer = new StringWriter();
|
||||
serializer.Serialize(buffer, z);
|
||||
|
||||
YamlSerializer<IEnumerable<Z>> deserializer = new YamlSerializer<IEnumerable<Z>>();
|
||||
IEnumerable<Z> result = deserializer.Deserialize(new StringReader(buffer.ToString()));
|
||||
var deserializer = new Deserializer();
|
||||
var result = (IEnumerable<Z>)deserializer.Deserialize(new StringReader(buffer.ToString()), typeof(IEnumerable<Z>));
|
||||
Assert.Equal(1, result.Count());
|
||||
Assert.Equal("Yo", result.First().aaa);
|
||||
}
|
||||
|
@ -437,7 +437,7 @@ namespace YamlDotNet.UnitTests.RepresentationModel
|
|||
DeserializationOptions options = new DeserializationOptions();
|
||||
options.Overrides.Add(typeof(Z), "aaa", (t, reader) => ((Z)t).aaa = reader.Expect<Scalar>().Value.ToUpperInvariant());
|
||||
|
||||
YamlSerializer serializer = new YamlSerializer();
|
||||
var serializer = new YamlSerializer();
|
||||
object result = serializer.Deserialize(YamlFile("explicitType.yaml"), options);
|
||||
|
||||
Assert.True(typeof(Z).IsAssignableFrom(result.GetType()));
|
||||
|
@ -466,7 +466,7 @@ namespace YamlDotNet.UnitTests.RepresentationModel
|
|||
DeserializationOptions options = new DeserializationOptions();
|
||||
options.Mappings.Add("tag:yaml.org,2002:point", typeof(Point));
|
||||
|
||||
YamlSerializer serializer = new YamlSerializer();
|
||||
var serializer = new YamlSerializer();
|
||||
object result = serializer.Deserialize(YamlFile("tags.yaml"), options);
|
||||
|
||||
Assert.Equal(typeof(Point), result.GetType());
|
||||
|
|
Загрузка…
Ссылка в новой задаче