Start to rewrite serialization (WIP)

This commit is contained in:
Alexandre Mutel 2013-10-05 00:20:53 +09:00
Родитель 8bee539624
Коммит df7c220db8
43 изменённых файлов: 1961 добавлений и 73 удалений

Просмотреть файл

@ -66,7 +66,7 @@
<ItemGroup>
<ProjectReference Include="..\YamlDotNet\YamlDotNet.csproj">
<Project>{BF32DE1B-6276-4341-B212-F8862ADBBA7A}</Project>
<Name>YamlDotNet.Core</Name>
<Name>YamlDotNet</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -78,7 +78,7 @@
<ItemGroup>
<ProjectReference Include="..\YamlDotNet\YamlDotNet.csproj">
<Project>{BF32DE1B-6276-4341-B212-F8862ADBBA7A}</Project>
<Name>YamlDotNet.Core</Name>
<Name>YamlDotNet</Name>
</ProjectReference>
<ProjectReference Include="..\YamlDotNet.RepresentationModel\YamlDotNet.Serialzation.csproj">
<Project>{21CA0077-E15C-446D-9C43-F6D3F9D09687}</Project>

Просмотреть файл

@ -61,9 +61,9 @@
<Project>{6a8dcaf7-6c13-4ada-aed9-7aba88fe7717}</Project>
<Name>YamlDotNet.Converters</Name>
</ProjectReference>
<ProjectReference Include="..\YamlDotNet.Core.Test\YamlDotNet.Core.Test.csproj">
<ProjectReference Include="..\YamlDotNet.Core.Test\YamlDotNet.Test.csproj">
<Project>{16d8043d-c3db-4868-bff3-b2ebdf537aaa}</Project>
<Name>YamlDotNet.Core.Test</Name>
<Name>YamlDotNet.Test</Name>
</ProjectReference>
<ProjectReference Include="..\YamlDotNet.RepresentationModel\YamlDotNet.Serialzation.csproj">
<Project>{21ca0077-e15c-446d-9c43-f6d3f9d09687}</Project>

Просмотреть файл

@ -32,7 +32,7 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="FakeItEasy">
<Reference Include="FakeItEasy">
<HintPath>..\packages\FakeItEasy.1.13.1\lib\net40\FakeItEasy.dll</HintPath>
</Reference>
<Reference Include="FluentAssertions">
@ -100,11 +100,7 @@
<ItemGroup>
<ProjectReference Include="..\YamlDotNet\YamlDotNet.csproj">
<Project>{bf32de1b-6276-4341-b212-f8862adbba7a}</Project>
<Name>YamlDotNet.Core</Name>
</ProjectReference>
<ProjectReference Include="..\YamlDotNet.RepresentationModel\YamlDotNet.Serialzation.csproj">
<Project>{21ca0077-e15c-446d-9c43-f6d3f9d09687}</Project>
<Name>YamlDotNet.Serialzation</Name>
<Name>YamlDotNet</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

Просмотреть файл

@ -65,13 +65,13 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\YamlDotNet.Core.Test\YamlDotNet.Core.Test.csproj">
<ProjectReference Include="..\YamlDotNet.Core.Test\YamlDotNet.Test.csproj">
<Project>{16d8043d-c3db-4868-bff3-b2ebdf537aaa}</Project>
<Name>YamlDotNet.Core.Test</Name>
<Name>YamlDotNet.Test</Name>
</ProjectReference>
<ProjectReference Include="..\YamlDotNet\YamlDotNet.csproj">
<Project>{bf32de1b-6276-4341-b212-f8862adbba7a}</Project>
<Name>YamlDotNet.Core</Name>
<Name>YamlDotNet</Name>
</ProjectReference>
<ProjectReference Include="..\YamlDotNet.RepresentationModel\YamlDotNet.Serialzation.csproj">
<Project>{21ca0077-e15c-446d-9c43-f6d3f9d09687}</Project>

Просмотреть файл

@ -56,7 +56,7 @@
<ItemGroup>
<ProjectReference Include="..\YamlDotNet\YamlDotNet.csproj">
<Project>{BF32DE1B-6276-4341-B212-F8862ADBBA7A}</Project>
<Name>YamlDotNet.Core</Name>
<Name>YamlDotNet</Name>
</ProjectReference>
<ProjectReference Include="..\YamlDotNet.RepresentationModel\YamlDotNet.Serialzation.csproj">
<Project>{21CA0077-E15C-446D-9C43-F6D3F9D09687}</Project>

Просмотреть файл

@ -34,14 +34,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{8DC198
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YamlDotNet.Converters.Test", "YamlDotNet.Converters.Test\YamlDotNet.Converters.Test.csproj", "{F0EAB124-9790-41C7-AE0F-F050CA0141D3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YamlDotNet.Core.Test", "YamlDotNet.Core.Test\YamlDotNet.Core.Test.csproj", "{16D8043D-C3DB-4868-BFF3-B2EBDF537AAA}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YamlDotNet.Test", "YamlDotNet.Core.Test\YamlDotNet.Test.csproj", "{16D8043D-C3DB-4868-BFF3-B2EBDF537AAA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YamlDotNet.RepresentationModel.Test", "YamlDotNet.RepresentationModel.Test\YamlDotNet.RepresentationModel.Test.csproj", "{FF969DAA-C025-4636-89B2-46F16821FA02}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YamlDotNet.Dynamic", "YamlDotNet.Dynamic\YamlDotNet.Dynamic.csproj", "{57B52D79-04A0-4091-8EE2-B419C009C2A6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestTag", "TestTag\TestTag.csproj", "{453D508D-E938-4C75-A852-05A05945472E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YamlDotNet.Dynamic.UnitTests", "YamlDotNet.Dynamic.UnitTests\YamlDotNet.Dynamic.UnitTests.csproj", "{6E3BEF5A-2DBA-4941-972D-BD6AF27B4A71}"
EndProject
Global
@ -113,6 +111,7 @@ Global
{16D8043D-C3DB-4868-BFF3-B2EBDF537AAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{16D8043D-C3DB-4868-BFF3-B2EBDF537AAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{16D8043D-C3DB-4868-BFF3-B2EBDF537AAA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{16D8043D-C3DB-4868-BFF3-B2EBDF537AAA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{16D8043D-C3DB-4868-BFF3-B2EBDF537AAA}.Debug|x86.ActiveCfg = Debug|Any CPU
{16D8043D-C3DB-4868-BFF3-B2EBDF537AAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{16D8043D-C3DB-4868-BFF3-B2EBDF537AAA}.Release|Any CPU.Build.0 = Release|Any CPU
@ -137,15 +136,6 @@ Global
{57B52D79-04A0-4091-8EE2-B419C009C2A6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{57B52D79-04A0-4091-8EE2-B419C009C2A6}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{57B52D79-04A0-4091-8EE2-B419C009C2A6}.Release|x86.ActiveCfg = Release|Any CPU
{453D508D-E938-4C75-A852-05A05945472E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{453D508D-E938-4C75-A852-05A05945472E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{453D508D-E938-4C75-A852-05A05945472E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{453D508D-E938-4C75-A852-05A05945472E}.Debug|x86.ActiveCfg = Debug|Any CPU
{453D508D-E938-4C75-A852-05A05945472E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{453D508D-E938-4C75-A852-05A05945472E}.Release|Any CPU.Build.0 = Release|Any CPU
{453D508D-E938-4C75-A852-05A05945472E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{453D508D-E938-4C75-A852-05A05945472E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{453D508D-E938-4C75-A852-05A05945472E}.Release|x86.ActiveCfg = Release|Any CPU
{6E3BEF5A-2DBA-4941-972D-BD6AF27B4A71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6E3BEF5A-2DBA-4941-972D-BD6AF27B4A71}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6E3BEF5A-2DBA-4941-972D-BD6AF27B4A71}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU

Просмотреть файл

@ -20,15 +20,12 @@
// SOFTWARE.
using System;
using System.Runtime.Serialization;
using YamlDotNet;
namespace YamlDotNet.Serialization
{
/// <summary>
/// The exception that is thrown when an alias references an anchor that does not exist.
/// </summary>
[Serializable]
public class AnchorNotFoundException : YamlException
{
/// <summary>

Просмотреть файл

@ -0,0 +1,33 @@
using System;
namespace YamlDotNet.Serialization
{
/// <summary>
/// A descriptor for an array.
/// </summary>
public class ArrayDescriptor : ObjectDescriptor
{
private readonly Type elementType;
/// <summary>
/// Initializes a new instance of the <see cref="ObjectDescriptor" /> class.
/// </summary>
/// <param name="settings">The settings.</param>
/// <param name="type">The type.</param>
public ArrayDescriptor(YamlSerializerSettings settings, Type type)
: base(settings, type)
{
if (!type.IsArray) throw new ArgumentException("Expecting arrat type", "type");
elementType = type.GetElementType();
// TODO handle dimensions
}
/// <summary>
/// Gets the type of the array element.
/// </summary>
/// <value>The type of the element.</value>
public Type ElementType { get { return elementType; } }
}
}

Просмотреть файл

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
namespace YamlDotNet.Serialization
{
/// <summary>
/// Provides a descriptor for a <see cref="System.Collections.ICollection"/>.
/// </summary>
public class CollectionDescriptor : ObjectDescriptor
{
/// <summary>
/// Initializes a new instance of the <see cref="CollectionDescriptor" /> class.
/// </summary>
/// <param name="settings">The settings.</param>
/// <param name="type">The type.</param>
public CollectionDescriptor(YamlSerializerSettings settings, Type type) : base(settings, type)
{
}
protected override List<IMemberDescriptor> PrepareMembers()
{
var members = base.PrepareMembers();
// In case we are not emitting List.Capacity, we need to remove them from the member list
if (!Settings.EmitCapacityForList)
{
for (int i = members.Count - 1; i >= 0; i--)
{
if (members[i].Name == "Capacity" && members[i].Type == typeof (int))
{
members.RemoveAt(i);
break;
}
}
}
return members;
}
}
}

Просмотреть файл

@ -0,0 +1,130 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace YamlDotNet.Serialization
{
/// <summary>
/// A default implementation for <see cref="IAttributeRegistry"/>.
/// This implementation allows to retrieve default attributes for a member or
/// to attach an attribute to a specific type/member.
/// </summary>
public class DefaultAttributeRegistry : IAttributeRegistry
{
private readonly Dictionary<MemberInfoKey, List<Attribute>> cachedAttributes = new Dictionary<MemberInfoKey, List<Attribute>>();
private readonly Dictionary<MemberInfo, List<Attribute>> registeredAttributes = new Dictionary<MemberInfo, List<Attribute>>();
/// <summary>
/// Gets the attributes associated with the specified member.
/// </summary>
/// <param name="memberInfo">The reflection member.</param>
/// <param name="inherit">if set to <c>true</c> includes inherited attributes.</param>
/// <returns>An enumeration of <see cref="Attribute"/>.</returns>
public List<Attribute> GetAttributes(MemberInfo memberInfo, bool inherit = true)
{
var key = new MemberInfoKey(memberInfo, inherit);
// Use a cache of attributes
List<Attribute> attributes;
if (cachedAttributes.TryGetValue(key, out attributes))
{
return attributes;
}
// Else retrieve all default attributes
var defaultAttributes = memberInfo.GetCustomAttributes(inherit);
attributes = defaultAttributes.Cast<Attribute>().ToList();
// And add registered attributes
List<Attribute> registered;
if (registeredAttributes.TryGetValue(memberInfo, out registered))
{
attributes.AddRange(registered);
}
// Add to the cache
cachedAttributes.Add(key, attributes);
return attributes;
}
/// <summary>
/// Gets the attributes associated with the specified member.
/// </summary>
/// <typeparam name="T">Type of the attribute</typeparam>
/// <param name="memberInfo">The member information.</param>
/// <param name="inherit">if set to <c>true</c> [inherit].</param>
/// <returns>An enumeration of <see cref="Attribute"/>.</returns>
public IEnumerable<T> GetAttributes<T>(MemberInfo memberInfo, bool inherit = true) where T : Attribute
{
return GetAttributes(memberInfo, inherit).OfType<T>();
}
/// <summary>
/// Gets an attribute associated with the specified member.
/// </summary>
/// <typeparam name="T">Type of the attribute</typeparam>
/// <param name="memberInfo">The member information.</param>
/// <param name="inherit">if set to <c>true</c> [inherit].</param>
/// <returns>An attribute of type {T} if it was found; otherwise <c>null</c> </returns>
public T GetAttribute<T>(MemberInfo memberInfo, bool inherit = true) where T : Attribute
{
var list = GetAttributes(memberInfo, inherit);
if (list.Count > 0)
{
return list[list.Count - 1] as T;
}
return null;
}
/// <summary>
/// Registers an attribute for the specified member. Restriction: Attributes registered this way cannot be listed in inherited attributes.
/// </summary>
/// <param name="memberInfo">The member information.</param>
/// <param name="attribute">The attribute.</param>
public void Register(MemberInfo memberInfo, Attribute attribute)
{
List<Attribute> attributes;
if (!registeredAttributes.TryGetValue(memberInfo, out attributes))
{
attributes = new List<Attribute>();
registeredAttributes.Add(memberInfo, attributes);
}
attributes.Add(attribute);
}
private struct MemberInfoKey : IEquatable<MemberInfoKey>
{
private readonly MemberInfo memberInfo;
private readonly bool inherit;
public MemberInfoKey(MemberInfo memberInfo, bool inherit)
{
this.memberInfo = memberInfo;
this.inherit = inherit;
}
public bool Equals(MemberInfoKey other)
{
return memberInfo.Equals(other.memberInfo) && inherit.Equals(other.inherit);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
return obj is MemberInfoKey && Equals((MemberInfoKey) obj);
}
public override int GetHashCode()
{
unchecked
{
return (memberInfo.GetHashCode()*397) ^ inherit.GetHashCode();
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,62 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace YamlDotNet.Serialization
{
/// <summary>
/// Class DefaultDescriptorFactory.
/// </summary>
public class DefaultDescriptorFactory : ITypeDescriptorFactory
{
private readonly YamlSerializerSettings settings;
protected readonly Dictionary<Type,ITypeDescriptor> RegisteredDescriptors = new Dictionary<Type, ITypeDescriptor>();
/// <summary>
/// Initializes a new instance of the <see cref="DefaultDescriptorFactory"/> class.
/// </summary>
/// <param name="settings">The settings.</param>
public DefaultDescriptorFactory(YamlSerializerSettings settings)
{
this.settings = settings;
}
public virtual ITypeDescriptor Find(Type type)
{
if (type == null)
return null;
ITypeDescriptor descriptor;
if (RegisteredDescriptors.TryGetValue(type, out descriptor))
{
return descriptor;
}
if (typeof (IDictionary).IsAssignableFrom(type))
{
// IDictionary
descriptor = new DictionaryDescriptor(settings, type);
}
else if (typeof (ICollection).IsAssignableFrom(type))
{
// ICollection
descriptor = new CollectionDescriptor(settings, type);
}
else if (type.IsArray)
{
// array[]
descriptor = new ArrayDescriptor(settings, type);
}
else
{
// standard object (class or value type)
descriptor = new ObjectDescriptor(settings, type);
}
// Register this descriptor
RegisteredDescriptors.Add(type, descriptor);
return descriptor;
}
}
}

Просмотреть файл

@ -0,0 +1,64 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace YamlDotNet.Serialization
{
/// <summary>
/// Provides a descriptor for a <see cref="System.Collections.IDictionary"/>.
/// </summary>
public class DictionaryDescriptor : ObjectDescriptor
{
private readonly Type keyType;
private readonly Type valueType;
/// <summary>
/// Initializes a new instance of the <see cref="DictionaryDescriptor" /> class.
/// </summary>
/// <param name="settings">The serializer settings.</param>
/// <param name="type">The type.</param>
public DictionaryDescriptor(YamlSerializerSettings settings, Type type) : base(settings, type)
{
// extract Key, Value types from IDictionary<??, ??>
var interfaceType = type.GetInterface(typeof(IDictionary<,>));
if (interfaceType != null)
{
keyType = interfaceType.GetGenericArguments()[0];
valueType = interfaceType.GetGenericArguments()[1];
}
else
{
keyType = typeof(object);
valueType = typeof(object);
}
}
/// <summary>
/// Gets the type of the key.
/// </summary>
/// <value>The type of the key.</value>
public Type KeyType
{
get { return keyType; }
}
/// <summary>
/// Gets the type of the value.
/// </summary>
/// <value>The type of the value.</value>
public Type ValueType
{
get { return valueType; }
}
/// <summary>
/// Determines whether the value passed is readonly.
/// </summary>
/// <param name="thisObject">The this object.</param>
/// <returns><c>true</c> if [is read only] [the specified this object]; otherwise, <c>false</c>.</returns>
public bool IsReadOnly(object thisObject)
{
return ((IDictionary)thisObject).IsReadOnly;
}
}
}

Просмотреть файл

@ -20,15 +20,12 @@
// SOFTWARE.
using System;
using System.Runtime.Serialization;
using YamlDotNet;
namespace YamlDotNet.Serialization
{
/// <summary>
/// The exception that is thrown when a duplicate anchor is detected.
/// </summary>
[Serializable]
public class DuplicateAnchorException : YamlException
{
/// <summary>

Просмотреть файл

@ -1,5 +1,4 @@
using System;
using YamlDotNet;
using YamlDotNet.Events;
namespace YamlDotNet.Serialization

Просмотреть файл

@ -0,0 +1,62 @@
using System;
using System.Reflection;
namespace YamlDotNet.Serialization
{
/// <summary>
/// A <see cref="IMemberDescriptor"/> for a <see cref="FieldInfo"/>
/// </summary>
public class FieldDescriptor : MemberDescriptorBase
{
private readonly FieldInfo fieldInfo;
/// <summary>
/// Initializes a new instance of the <see cref="FieldDescriptor"/> class.
/// </summary>
/// <param name="fieldInfo">The property information.</param>
public FieldDescriptor(FieldInfo fieldInfo) : base(fieldInfo)
{
if (fieldInfo == null) throw new ArgumentNullException("fieldInfo");
this.fieldInfo = fieldInfo;
}
/// <summary>
/// Gets the property information attached to this instance.
/// </summary>
/// <value>The property information.</value>
public FieldInfo FieldInfo
{
get { return fieldInfo; }
}
public override Type Type
{
get { return fieldInfo.FieldType; }
}
public override object Get(object thisObject)
{
return fieldInfo.GetValue(thisObject);
}
public override void Set(object thisObject, object value)
{
fieldInfo.SetValue(thisObject, value);
}
public override bool HasSet
{
get { return true; }
}
/// <summary>
/// Returns a <see cref="System.String" /> that represents this instance.
/// </summary>
/// <returns>A <see cref="System.String" /> that represents this instance.</returns>
public override string ToString()
{
return string.Format("Field [{0}] from Type [{1}]", Name, FieldInfo.DeclaringType != null ? FieldInfo.DeclaringType.FullName : string.Empty);
}
}
}

Просмотреть файл

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace YamlDotNet.Serialization
{
/// <summary>
/// A registry for all attributes.
/// </summary>
public interface IAttributeRegistry
{
/// <summary>
/// Gets the attributes associated with the specified member.
/// </summary>
/// <param name="memberInfo">The reflection member.</param>
/// <param name="inherit">if set to <c>true</c> includes inherited attributes.</param>
/// <returns>An enumeration of <see cref="Attribute"/>.</returns>
List<Attribute> GetAttributes(MemberInfo memberInfo, bool inherit = true);
/// <summary>
/// Gets the attributes associated with the specified member.
/// </summary>
/// <typeparam name="T">Type of the attribute</typeparam>
/// <param name="memberInfo">The member information.</param>
/// <param name="inherit">if set to <c>true</c> [inherit].</param>
/// <returns>An enumeration of <see cref="Attribute"/>.</returns>
IEnumerable<T> GetAttributes<T>(MemberInfo memberInfo, bool inherit = true) where T : Attribute;
/// <summary>
/// Gets an attribute associated with the specified member.
/// </summary>
/// <typeparam name="T">Type of the attribute</typeparam>
/// <param name="memberInfo">The member information.</param>
/// <param name="inherit">if set to <c>true</c> [inherit].</param>
/// <returns>An attribute of type {T} if it was found; otherwise <c>null</c> </returns>
T GetAttribute<T>(MemberInfo memberInfo, bool inherit = true) where T : Attribute;
/// <summary>
/// Registers an attribute for the specified member. Restriction: Attributes registered this way cannot be listed in inherited attributes.
/// </summary>
/// <param name="memberInfo">The member information.</param>
/// <param name="attribute">The attribute.</param>
void Register(MemberInfo memberInfo, Attribute attribute);
}
}

Просмотреть файл

@ -1,12 +1,20 @@
namespace YamlDotNet.Serialization
{
/// <summary>
/// Interface used to write YAML events.
/// </summary>
public interface IEventEmitter
{
void Emit(AliasEventInfo eventInfo);
void Emit(ScalarEventInfo eventInfo);
void Emit(MappingStartEventInfo eventInfo);
void Emit(MappingEndEventInfo eventInfo);
void Emit(SequenceStartEventInfo eventInfo);
void Emit(SequenceEndEventInfo eventInfo);
}
}

Просмотреть файл

@ -0,0 +1,54 @@
using System;
namespace YamlDotNet.Serialization
{
/// <summary>
/// Describe a member of an object.
/// </summary>
public interface IMemberDescriptor
{
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
string Name { get; }
/// <summary>
/// Gets the type.
/// </summary>
/// <value>The type.</value>
Type Type { get; }
/// <summary>
/// Gets the mode of serialization for this member.
/// </summary>
/// <value>The mode.</value>
SerializeMemberMode SerializeMemberMode { get; }
/// <summary>
/// Gets the value of this memeber for the specified instance.
/// </summary>
/// <param name="thisObject">The this object to get the value from.</param>
/// <returns>Value of the member.</returns>
object Get(object thisObject);
/// <summary>
/// Sets a value of this memeber for the specified instance.
/// </summary>
/// <param name="thisObject">The this object.</param>
/// <param name="value">The value.</param>
void Set(object thisObject, object value);
/// <summary>
/// Gets a value indicating whether this instance has set method.
/// </summary>
/// <value><c>true</c> if this instance has set method; otherwise, <c>false</c>.</value>
bool HasSet { get; }
/// <summary>
/// Gets a value indicating whether this member should be serialized.
/// </summary>
/// <value><c>true</c> if [should serialize]; otherwise, <c>false</c>.</value>
Func<object, bool> ShouldSerialize { get; }
}
}

Просмотреть файл

@ -1,22 +1,49 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace YamlDotNet.Serialization
{
/// <summary>
/// Provides access to the properties of a type.
/// Provides access members of a type.
/// </summary>
public interface ITypeDescriptor
{
IEnumerable<IPropertyDescriptor> GetProperties(Type type);
/// <summary>
/// Gets the type described by this instance.
/// </summary>
/// <value>The type.</value>
Type Type { get; }
IPropertyDescriptor GetProperty(Type type, string name);
}
/// <summary>
/// Gets the members of this type.
/// </summary>
/// <value>The members.</value>
IEnumerable<IMemberDescriptor> Members { get; }
public interface IPropertyDescriptor
{
string Name { get; }
PropertyInfo Property { get; }
/// <summary>
/// Gets the member count.
/// </summary>
/// <value>The member count.</value>
int Count { get; }
/// <summary>
/// Gets a value indicating whether this instance has members.
/// </summary>
/// <value><c>true</c> if this instance has members; otherwise, <c>false</c>.</value>
bool HasMembers { get; }
/// <summary>
/// Gets the <see cref="IMemberDescriptor"/> with the specified name.
/// </summary>
/// <param name="name">The name.</param>
/// <returns>The member.</returns>
IMemberDescriptor this[string name] { get; }
/// <summary>
/// Determines whether this instance contains a member with the specified member name.
/// </summary>
/// <param name="memberName">Name of the member.</param>
/// <returns><c>true</c> if this instance contains a member with the specified member name; otherwise, <c>false</c>.</returns>
bool Contains(string memberName);
}
}

Просмотреть файл

@ -0,0 +1,17 @@
using System;
namespace YamlDotNet.Serialization
{
/// <summary>
/// A factory to create an instance of a <see cref="ITypeDescriptor"/>
/// </summary>
public interface ITypeDescriptorFactory
{
/// <summary>
/// Tries to create an instance of a <see cref="ITypeDescriptor"/> from the type. Return null if this factory is not handling this type.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>ITypeDescriptor.</returns>
ITypeDescriptor Find(Type type);
}
}

Просмотреть файл

@ -20,23 +20,29 @@
// SOFTWARE.
using System;
using YamlDotNet;
namespace YamlDotNet.Serialization
{
/// <summary>
/// Allows an object to customize how it is serialized and deserialized.
/// </summary>
public interface IYamlSerializable
public interface IYamlProcessor
{
/// <summary>
/// Reads this object's state from a YAML parser.
/// </summary>
void ReadYaml(IParser parser);
/// <param name="context">The context.</param>
/// <param name="value"></param>
/// <param name="expectedType">Expected type. May be null.</param>
/// <returns>A instance of the object deserialized from Yaml.</returns>
object ReadYaml(SerializerContext context, object value, Type expectedType);
/// <summary>
/// Writes this object's state to a YAML emitter.
/// </summary>
void WriteYaml(IEmitter emitter);
/// <param name="context">The context.</param>
/// <param name="value">The value.</param>
/// <param name="type">The type.</param>
void WriteYaml(SerializerContext context, object value, Type type);
}
}

Просмотреть файл

@ -0,0 +1,18 @@
using System;
namespace YamlDotNet.Serialization
{
/// <summary>
/// A factory of <see cref="IYamlProcessor"/>
/// </summary>
public interface IYamlSerializableFactory
{
/// <summary>
/// Try to create a <see cref="IYamlProcessor"/> or return null if not supported for a particular .NET type.
/// </summary>
/// <param name="context"></param>
/// <param name="type">The type.</param>
/// <returns>If supported, return an instance of <see cref="IYamlProcessor"/> else return <c>null</c>.</returns>
IYamlProcessor TryCreate(SerializerContext context, Type type);
}
}

Просмотреть файл

@ -0,0 +1,18 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace YamlDotNet.Serialization
{
internal class IdentityEqualityComparer<T> : IEqualityComparer<T> where T : class
{
public bool Equals(T left, T right)
{
return ReferenceEquals(left, right);
}
public int GetHashCode(T value)
{
return RuntimeHelpers.GetHashCode(value);
}
}
}

Просмотреть файл

@ -0,0 +1,33 @@
using System;
using System.Reflection;
namespace YamlDotNet.Serialization
{
/// <summary>
/// Base class for <see cref="IMemberDescriptor"/> for a <see cref="MemberInfo"/>
/// </summary>
public abstract class MemberDescriptorBase : IMemberDescriptor
{
protected MemberDescriptorBase(MemberInfo memberInfo)
{
if (memberInfo == null) throw new ArgumentNullException("memberInfo");
MemberInfo = memberInfo;
Name = MemberInfo.Name;
}
public string Name { get; internal set; }
public abstract Type Type { get; }
public SerializeMemberMode SerializeMemberMode { get; internal set; }
public abstract object Get(object thisObject);
public abstract void Set(object thisObject, object value);
public abstract bool HasSet { get; }
public Func<object, bool> ShouldSerialize { get; internal set; }
/// <summary>
/// Gets the member information.
/// </summary>
/// <value>The member information.</value>
public MemberInfo MemberInfo { get; private set; }
}
}

Просмотреть файл

@ -0,0 +1,183 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
namespace YamlDotNet.Serialization
{
/// <summary>
/// Default implementation of a <see cref="ITypeDescriptor"/>.
/// </summary>
public class ObjectDescriptor : ITypeDescriptor
{
private readonly static object[] EmptyObjectArray = new object[0];
private readonly YamlSerializerSettings settings;
private readonly Type type;
private readonly IMemberDescriptor[] members;
private readonly Dictionary<string, IMemberDescriptor> mapMembers;
/// <summary>
/// Initializes a new instance of the <see cref="ObjectDescriptor" /> class.
/// </summary>
/// <param name="settings">The settings.</param>
/// <param name="type">The type.</param>
/// <exception cref="YamlException">Failed to get ObjectDescriptor for type [{0}]. The member [{1}] cannot be registered as a member with the same name is already registered [{2}].DoFormat(type.FullName, member, existingMember)</exception>
public ObjectDescriptor(YamlSerializerSettings settings, Type type)
{
if (settings == null) throw new ArgumentNullException("settings");
if (type == null) throw new ArgumentNullException("type");
this.settings = settings;
this.type = type;
this.members = PrepareMembers().ToArray();
// If no members found, we don't need to build a dictionary map
if (members.Length <= 0) return;
mapMembers = new Dictionary<string, IMemberDescriptor>(members.Length);
foreach (var member in Members)
{
IMemberDescriptor existingMember;
if (mapMembers.TryGetValue(member.Name, out existingMember))
{
throw new YamlException("Failed to get ObjectDescriptor for type [{0}]. The member [{1}] cannot be registered as a member with the same name is already registered [{2}]".DoFormat(type.FullName, member, existingMember));
}
mapMembers.Add(member.Name, member);
}
}
public Type Type
{
get { return type; }
}
public IEnumerable<IMemberDescriptor> Members
{
get { return members; }
}
public int Count
{
get { return members.Length; }
}
public bool HasMembers
{
get { return members.Length > 0; }
}
public IMemberDescriptor this[string name]
{
get
{
if (mapMembers == null) throw new KeyNotFoundException(name);
return mapMembers[name];
}
}
public bool Contains(string memberName)
{
return mapMembers != null && mapMembers.ContainsKey(memberName);
}
protected YamlSerializerSettings Settings
{
get { return settings; }
}
protected virtual List<IMemberDescriptor> PrepareMembers()
{
// Add all public properties with a readable get method
var memberList = (from propertyInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
where
propertyInfo.CanRead && propertyInfo.GetGetMethod(false) != null &&
propertyInfo.GetIndexParameters().Length == 0
select new PropertyDescriptor(propertyInfo)
into member
where PrepareMember(member)
select member).Cast<IMemberDescriptor>().ToList();
// Add all public fields
memberList.AddRange((from fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public)
where fieldInfo.IsPublic
select new FieldDescriptor(fieldInfo)
into member where PrepareMember(member) select member));
return memberList;
}
private bool PrepareMember(MemberDescriptorBase member)
{
// If the member has a set, this is a conventional assign method
if (member.HasSet)
{
member.SerializeMemberMode = SerializeMemberMode.Assign;
}
else
{
// Else we cannot only assign its content if it is a class
member.SerializeMemberMode = type.IsClass ? SerializeMemberMode.Content : SerializeMemberMode.Never;
}
var attributeRegistry = Settings.AttributeRegistry;
// Member is not displayed if there is a YamlIgnore attribute on it
if (attributeRegistry.GetAttribute<YamlIgnoreAttribute>(member.MemberInfo, false) != null)
return false;
var memberAttribute = attributeRegistry.GetAttribute<YamlMemberAttribute>(member.MemberInfo, false);
if (memberAttribute != null)
{
if (!member.HasSet)
{
if (memberAttribute.SerializeMethod == SerializeMemberMode.Assign ||
(type.IsValueType && member.SerializeMemberMode == SerializeMemberMode.Content))
throw new ArgumentException("{0} {1} is not writeable by {2}.".DoFormat(type.FullName, member.Name, memberAttribute.SerializeMethod.ToString()));
}
member.SerializeMemberMode = memberAttribute.SerializeMethod;
}
if (member.SerializeMemberMode == SerializeMemberMode.Binary)
{
if (!type.IsArray)
throw new InvalidOperationException("{0} {1} of {2} is not an array. Can not be serialized as binary."
.DoFormat(type.FullName, member.Name, type.FullName));
if (!type.GetElementType().IsPureValueType())
throw new InvalidOperationException("{0} is not a pure ValueType. {1} {2} of {3} can not serialize as binary.".DoFormat(type.GetElementType(), type.FullName, member.Name, type.FullName));
}
// ShouldSerialize
// YamlSerializeAttribute(Never) => false
// ShouldSerializeSomeProperty => call it
// DefaultValueAttribute(default) => compare to it
// otherwise => true
var shouldSerialize = type.GetMethod("ShouldSerialize" + member.Name, BindingFlags.Instance | BindingFlags.NonPublic);
if (shouldSerialize != null && shouldSerialize.ReturnType == typeof(bool) && member.ShouldSerialize == null)
member.ShouldSerialize = obj => (bool)shouldSerialize.Invoke(obj, EmptyObjectArray);
var defaultValueAttribute = attributeRegistry.GetAttribute<DefaultValueAttribute>(member.MemberInfo);
if (defaultValueAttribute != null && member.ShouldSerialize == null)
{
object defaultValue = defaultValueAttribute.Value;
Type defaultType = defaultValue == null ? null : defaultValue.GetType();
if (defaultType.IsNumeric() && defaultType != type)
defaultValue = type.CastToNumericType(defaultValue);
member.ShouldSerialize = obj => !TypeExtensions.AreEqual(defaultValue, member.Get(obj));
}
if (member.ShouldSerialize == null)
member.ShouldSerialize = obj => true;
if (memberAttribute != null && !string.IsNullOrEmpty(memberAttribute.Name))
{
member.Name = memberAttribute.Name;
}
return true;
}
}
}

Просмотреть файл

@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using YamlDotNet.Events;
namespace YamlDotNet.Serialization
{
internal class AnchorProcessor : ChainedProcessor
{
private Dictionary<string, object> aliasToObject;
private Dictionary<object, string> objectToAlias;
public AnchorProcessor(IYamlProcessor next) : base(next)
{
}
public override object ReadYaml(SerializerContext context, object value, Type expectedType)
{
var reader = context.Reader;
// Process Anchor alias (*oxxx)
var alias = reader.Allow<AnchorAlias>();
if (alias != null)
{
if (!AliasToObject.TryGetValue(alias.Value, out value))
{
throw new YamlException("Alias [{0}] not found".DoFormat(alias.Value));
}
return value;
}
// Test if current node as an anchor
string anchor = null;
var nodeEvent = reader.Peek<NodeEvent>();
if (nodeEvent != null && !string.IsNullOrEmpty(nodeEvent.Anchor))
{
anchor = nodeEvent.Anchor;
}
// Deserialize the current node
value = base.ReadYaml(context, value, expectedType);
// Store Anchor (&oxxx) and override any defined anchor
if (anchor != null)
{
AliasToObject[anchor] = value;
}
return value;
}
public override void WriteYaml(SerializerContext context, object value, Type type)
{
if (value != null && Type.GetTypeCode(value.GetType()) == TypeCode.Object)
{
string alias;
if (ObjectToString.TryGetValue(value, out alias))
{
context.Writer.Emit(new AliasEventInfo(value, type) {Alias = alias});
return;
}
else
{
alias = string.Format("o{0}", context.AnchorCount);
ObjectToString.Add(value, alias);
// Store the alias in the context
context.Anchors.Push(alias);
context.AnchorCount++;
}
}
base.WriteYaml(context, value, type);
}
private Dictionary<string, object> AliasToObject
{
get { return aliasToObject ?? (aliasToObject = new Dictionary<string, object>()); }
}
private Dictionary<object, string> ObjectToString
{
get { return objectToAlias ?? (objectToAlias = new Dictionary<object, string>(new IdentityEqualityComparer<object>())); }
}
}
}

Просмотреть файл

@ -0,0 +1,25 @@
using System;
namespace YamlDotNet.Serialization
{
internal class ChainedProcessor : IYamlProcessor
{
private readonly IYamlProcessor next;
public ChainedProcessor(IYamlProcessor next)
{
if (next == null) throw new ArgumentNullException("next");
this.next = next;
}
public virtual object ReadYaml(SerializerContext context, object value, Type expectedType)
{
return next.ReadYaml(context, value, expectedType);
}
public virtual void WriteYaml(SerializerContext context, object value, Type type)
{
next.WriteYaml(context, value, type);
}
}
}

Просмотреть файл

@ -0,0 +1,114 @@
using System;
using System.Collections;
using System.Linq;
using YamlDotNet.Events;
namespace YamlDotNet.Serialization
{
internal class DictionaryProcessor : ObjectProcessor
{
private readonly PureDictionaryProcessor pureDictionaryProcessor;
public DictionaryProcessor(YamlSerializerSettings settings) : base(settings)
{
pureDictionaryProcessor = new PureDictionaryProcessor(settings);
}
protected override void ReadItem(SerializerContext context, object thisObject, ITypeDescriptor typeDescriptor)
{
var dictionary = (IDictionary) thisObject;
var dictionaryDescriptor = (DictionaryDescriptor) typeDescriptor;
if (!dictionaryDescriptor.HasMembers)
{
var key = context.ReadYaml(null, dictionaryDescriptor.KeyType);
var value = context.ReadYaml(null, dictionaryDescriptor.ValueType);
dictionary.Add(key, value);
}
else
{
var keyEvent = context.Reader.Peek<Scalar>();
if (keyEvent != null)
{
if (keyEvent.Value == Settings.PrefixForItems)
{
pureDictionaryProcessor.ReadYaml(context, thisObject, thisObject.GetType());
return;
}
}
base.ReadItem(context, thisObject, typeDescriptor);
}
}
public override void WriteItems(SerializerContext context, object thisObject, ITypeDescriptor typeDescriptor)
{
if (!typeDescriptor.HasMembers)
{
pureDictionaryProcessor.WriteItems(context, thisObject, typeDescriptor);
}
else
{
// Serialize Dictionary members
foreach (var member in typeDescriptor.Members)
{
// Emit the key name
context.Writer.Emit(new ScalarEventInfo(member.Name, typeof(string)));
var memberValue = member.Get(thisObject);
var memberType = member.Type;
context.WriteYaml(memberValue, memberType);
}
context.Writer.Emit(new ScalarEventInfo(Settings.PrefixForItems, typeof(string)));
pureDictionaryProcessor.WriteYaml(context, thisObject, thisObject.GetType());
}
}
internal class PureDictionaryProcessor : ObjectProcessor
{
public PureDictionaryProcessor(YamlSerializerSettings settings) : base(settings)
{
}
protected override void ReadItem(SerializerContext context, object thisObject, ITypeDescriptor typeDescriptor)
{
var dictionary = (IDictionary)thisObject;
var dictionaryDescriptor = (DictionaryDescriptor)typeDescriptor;
var key = context.ReadYaml(null, dictionaryDescriptor.KeyType);
var value = context.ReadYaml(null, dictionaryDescriptor.ValueType);
dictionary.Add(key, value);
}
public override void WriteItems(SerializerContext context, object thisObject, ITypeDescriptor typeDescriptor)
{
var dictionary = (IDictionary) thisObject;
var dictionaryDescriptor = (DictionaryDescriptor)typeDescriptor;
var keys = dictionary.Keys;
if (context.Settings.SortKeyForMapping)
{
var sortedKeys = keys.Cast<object>().ToList();
sortedKeys.Sort((left, right) =>
{
if (left is IComparable && right is IComparable)
{
return ((IComparable) left).CompareTo(right);
}
return 0;
});
keys = sortedKeys;
}
var keyType = dictionaryDescriptor.KeyType;
var valueType = dictionaryDescriptor.ValueType;
foreach (var key in keys)
{
context.WriteYaml(key, keyType);
context.WriteYaml(dictionary[key], valueType);
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,139 @@
using System;
using YamlDotNet.Events;
namespace YamlDotNet.Serialization
{
public class ObjectProcessor : IYamlProcessor
{
private readonly YamlSerializerSettings settings;
public ObjectProcessor(YamlSerializerSettings settings)
{
if (settings == null) throw new ArgumentNullException("settings");
this.settings = settings;
}
public YamlSerializerSettings Settings
{
get { return settings; }
}
protected virtual bool IsSequence(ITypeDescriptor typeDescriptor)
{
return false;
}
public virtual object ReadYaml(SerializerContext context, object value, Type expectedType)
{
var reader = context.Reader;
var nodeEvent = reader.Peek<NodeEvent>();
var type = context.TypeFromTag(nodeEvent.Tag) ?? (value != null ? value.GetType() : expectedType);
if (type == null)
{
throw new YamlException("Unable to find type for mapping [{0}]".DoFormat(nodeEvent));
}
if (value == null)
{
value = context.CreateType(type);
if (value == null)
{
throw new YamlException("Unexpected null value");
}
}
// Get the object accessor for the corresponding class
var typeDescriptor = context.TypeDescriptorFactory.Find(value.GetType());
var isSequence = IsSequence(typeDescriptor);
if (isSequence)
{
ReadItems<SequenceStart,SequenceEnd>(context, value, typeDescriptor);
}
else
{
ReadItems<MappingStart, MappingEnd>(context, value, typeDescriptor);
}
return value;
}
protected virtual void ReadItems<TStart, TEnd>(SerializerContext context, object thisObject, ITypeDescriptor typeDescriptor)
where TStart : NodeEvent
where TEnd : ParsingEvent
{
var reader = context.Reader;
reader.Expect<TStart>();
while (!reader.Accept<TEnd>())
{
ReadItem(context, thisObject, typeDescriptor);
}
reader.Expect<TEnd>();
}
protected virtual void ReadItem(SerializerContext context, object thisObject, ITypeDescriptor typeDescriptor)
{
var reader = context.Reader;
// For a regular object, the key is expected to be a simple scalar
var propertyName = reader.Expect<Scalar>().Value;
var memberAccessor = typeDescriptor[propertyName];
// Read the value according to the type
var propertyType = memberAccessor.Type;
object value = null;
if (memberAccessor.SerializeMemberMode == SerializeMemberMode.Content)
{
value = memberAccessor.Get(thisObject);
}
var propertyValue = context.ReadYaml(value, propertyType);
if (memberAccessor.HasSet && memberAccessor.SerializeMemberMode != SerializeMemberMode.Content)
{
memberAccessor.Set(thisObject, propertyValue);
}
}
public virtual void WriteYaml(SerializerContext context, object value, Type type)
{
var typeOfValue = value.GetType();
var tag = typeOfValue == type ? null : context.TagFromType(typeOfValue);
// Get the object accessor for the corresponding class
var typeDescriptor = context.TypeDescriptorFactory.Find(typeOfValue);
var isSequence = IsSequence(typeDescriptor);
if (isSequence)
{
context.Writer.Emit(new SequenceStartEventInfo(value, typeOfValue) { Tag = tag });
WriteItems(context, value, typeDescriptor);
context.Writer.Emit(new SequenceEndEventInfo(value, typeOfValue));
}
else
{
context.Writer.Emit(new MappingStartEventInfo(value, typeOfValue) { Tag = tag });
WriteItems(context, value, typeDescriptor);
context.Writer.Emit(new MappingEndEventInfo(value, typeOfValue));
}
}
public virtual void WriteItems(SerializerContext context, object thisObject, ITypeDescriptor typeDescriptor)
{
foreach (var member in typeDescriptor.Members)
{
// Skip any member that we won't serialize
if (!member.ShouldSerialize(thisObject)) continue;
// Emit the key name
context.Writer.Emit(new ScalarEventInfo(member.Name, typeof (string)));
var memberValue = member.Get(thisObject);
var memberType = member.Type;
context.WriteYaml(memberValue, memberType);
}
}
}
}

Просмотреть файл

@ -3,26 +3,69 @@ using System.Reflection;
namespace YamlDotNet.Serialization
{
public sealed class PropertyDescriptor : IPropertyDescriptor
/// <summary>
/// A <see cref="IMemberDescriptor"/> for a <see cref="PropertyInfo"/>
/// </summary>
public class PropertyDescriptor : MemberDescriptorBase
{
public PropertyDescriptor(PropertyInfo property, string name)
private readonly PropertyInfo propertyInfo;
private readonly MethodInfo getMethod;
private readonly MethodInfo setMethod;
/// <summary>
/// Initializes a new instance of the <see cref="PropertyDescriptor"/> class.
/// </summary>
/// <param name="propertyInfo">The property information.</param>
public PropertyDescriptor(PropertyInfo propertyInfo) : base(propertyInfo)
{
if (property == null)
if (propertyInfo == null) throw new ArgumentNullException("propertyInfo");
this.propertyInfo = propertyInfo;
getMethod = propertyInfo.GetGetMethod(false);
if (propertyInfo.CanWrite && propertyInfo.GetSetMethod(false) != null)
{
throw new ArgumentNullException("property");
setMethod = propertyInfo.GetSetMethod(false);
}
Property = property;
if (name == null)
{
throw new ArgumentNullException("name");
}
Name = name;
}
public PropertyInfo Property { get; private set; }
public string Name { get; private set; }
/// <summary>
/// Gets the property information attached to this instance.
/// </summary>
/// <value>The property information.</value>
public PropertyInfo PropertyInfo
{
get { return propertyInfo; }
}
public override Type Type
{
get { return propertyInfo.PropertyType; }
}
public override object Get(object thisObject)
{
return getMethod.Invoke(thisObject, null);
}
public override void Set(object thisObject, object value)
{
if (HasSet)
setMethod.Invoke(thisObject, new [] {value});
}
public override bool HasSet
{
get { return setMethod != null; }
}
/// <summary>
/// Returns a <see cref="System.String" /> that represents this instance.
/// </summary>
/// <returns>A <see cref="System.String" /> that represents this instance.</returns>
public override string ToString()
{
return string.Format("Property [{0}] from Type [{1}]", Name, PropertyInfo.DeclaringType != null ? PropertyInfo.DeclaringType.FullName : string.Empty);
}
}
}

Просмотреть файл

@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
namespace YamlDotNet.Serialization
{
/// <summary>
/// A context used while deserializing.
/// </summary>
public class SerializerContext
{
private readonly YamlSerializerSettings settings;
private readonly TagRegistry tagRegistry;
private readonly ITypeDescriptorFactory typeDescriptorFactory;
/// <summary>
/// Initializes a new instance of the <see cref="SerializerContext"/> class.
/// </summary>
/// <param name="serializer">The serializer.</param>
internal SerializerContext(YamlSerializer serializer)
{
Serializer = serializer;
settings = serializer.Settings;
tagRegistry = serializer.TagRegistry;
typeDescriptorFactory = settings.TypeDescriptorFactory;
}
/// <summary>
/// Gets a value indicating whether we are in the context of serializing.
/// </summary>
/// <value><c>true</c> if we are in the context of serializing; otherwise, <c>false</c>.</value>
public bool IsSerializing
{
get { return Writer != null; }
}
/// <summary>
/// Gets the settings.
/// </summary>
/// <value>The settings.</value>
public YamlSerializerSettings Settings
{
get { return settings; }
}
/// <summary>
/// Gets the type descriptor factory.
/// </summary>
/// <value>The type descriptor factory.</value>
public ITypeDescriptorFactory TypeDescriptorFactory
{
get { return typeDescriptorFactory; }
}
/// <summary>
/// Gets the serializer.
/// </summary>
/// <value>The serializer.</value>
public YamlSerializer Serializer { get; private set; }
/// <summary>
/// Gets the reader used while deserializing.
/// </summary>
/// <value>The reader.</value>
public EventReader Reader { get; internal set; }
/// <summary>
/// The default function to read a Yaml.
/// </summary>
public Func<object, Type, object> ReadYaml { get; set; }
public Func<Type, object> CreateType { get; set; }
/// <summary>
/// Gets the writer used while deserializing.
/// </summary>
/// <value>The writer.</value>
public IEventEmitter Writer { get; internal set; }
/// <summary>
/// The default function to write an object to Yaml
/// </summary>
public Action<object, Type> WriteYaml { get; set; }
/// <summary>
/// Resolves a type from the specified tag.
/// </summary>
/// <param name="tagName">Name of the tag.</param>
/// <returns>Type.</returns>
public Type TypeFromTag(string tagName)
{
return tagRegistry.TypeFromTag(tagName);
}
/// <summary>
/// Resolves a tag from a type
/// </summary>
/// <param name="type">The type.</param>
/// <returns>The associated tag</returns>
public string TagFromType(Type type)
{
return tagRegistry.TagFromType(type);
}
internal string GetAnchor()
{
return Anchors.Count > 0 ? Anchors.Pop() : null;
}
internal Stack<string> Anchors = new Stack<string>();
internal int AnchorCount;
}
}

Просмотреть файл

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace YamlDotNet.Serialization
{
internal class TagRegistry
{
private readonly Dictionary<string, Type> tagToType;
private readonly Dictionary<Type, string> typeToTag;
private readonly List<Assembly> lookupAssemblies;
public TagRegistry(YamlSerializerSettings settings)
{
tagToType = new Dictionary<string, Type>(settings.TagToType);
typeToTag = new Dictionary<Type, string>(settings.TypeToTag);
lookupAssemblies = new List<Assembly>(settings.LookupAssemblies);
}
public Type TypeFromTag(string tagName)
{
if (tagName == null)
{
return null;
}
Type type;
if (tagToType.TryGetValue(tagName, out type))
{
return type;
}
type = Type.GetType(tagName);
if (type == null)
{
foreach (var assembly in lookupAssemblies)
{
type = assembly.GetType(tagName);
if (type != null)
{
break;
}
}
}
return type;
}
public string TagFromType(Type type)
{
string tagName;
if (!typeToTag.TryGetValue(type, out tagName))
{
return string.Format("!{0}", type.FullName);
}
return tagName;
}
}
}

Просмотреть файл

@ -6,10 +6,12 @@ namespace YamlDotNet.Serialization
public sealed class WriterEventEmitter : IEventEmitter
{
private readonly IEmitter emitter;
private readonly SerializerContext context;
public WriterEventEmitter(IEmitter emitter)
public WriterEventEmitter(IEmitter emitter, SerializerContext context)
{
this.emitter = emitter;
this.context = context;
}
void IEventEmitter.Emit(AliasEventInfo eventInfo)
@ -19,12 +21,12 @@ namespace YamlDotNet.Serialization
void IEventEmitter.Emit(ScalarEventInfo eventInfo)
{
emitter.Emit(new Scalar(eventInfo.Anchor, eventInfo.Tag, eventInfo.RenderedValue, eventInfo.Style, eventInfo.IsPlainImplicit, eventInfo.IsQuotedImplicit));
emitter.Emit(new Scalar(eventInfo.Anchor ?? context.GetAnchor(), eventInfo.Tag, eventInfo.RenderedValue, eventInfo.Style, eventInfo.IsPlainImplicit, eventInfo.IsQuotedImplicit));
}
void IEventEmitter.Emit(MappingStartEventInfo eventInfo)
{
emitter.Emit(new MappingStart(eventInfo.Anchor, eventInfo.Tag, eventInfo.IsImplicit, eventInfo.Style));
emitter.Emit(new MappingStart(eventInfo.Anchor ?? context.GetAnchor(), eventInfo.Tag, eventInfo.IsImplicit, eventInfo.Style));
}
void IEventEmitter.Emit(MappingEndEventInfo eventInfo)
@ -34,7 +36,7 @@ namespace YamlDotNet.Serialization
void IEventEmitter.Emit(SequenceStartEventInfo eventInfo)
{
emitter.Emit(new SequenceStart(eventInfo.Anchor, eventInfo.Tag, eventInfo.IsImplicit, eventInfo.Style));
emitter.Emit(new SequenceStart(eventInfo.Anchor ?? context.GetAnchor(), eventInfo.Tag, eventInfo.IsImplicit, eventInfo.Style));
}
void IEventEmitter.Emit(SequenceEndEventInfo eventInfo)

Просмотреть файл

@ -2,12 +2,12 @@ using System;
namespace YamlDotNet.Serialization
{
/// <summary>
/// Instructs the YamlSerializer not to serialize the public field or public read/write property value.
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
public sealed class YamlIgnoreAttribute : Attribute
{
}
/// <summary>
/// Instructs the YamlSerializer not to serialize the public field or public read/write property value.
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
public sealed class YamlIgnoreAttribute : Attribute
{
}
}

Просмотреть файл

@ -0,0 +1,63 @@
using System;
namespace YamlDotNet.Serialization
{
/// <summary>
/// Specify the way to store a property or field of some class or structure.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public sealed class YamlMemberAttribute : Attribute
{
private readonly SerializeMemberMode serializeMethod;
private readonly string name;
/// <summary>
/// Initializes a new instance of the <see cref="YamlMemberAttribute"/> class.
/// </summary>
/// <param name="name">The name.</param>
public YamlMemberAttribute(string name)
{
this.name = name;
serializeMethod = SerializeMemberMode.Assign;
}
/// <summary>
/// Specify the way to store a property or field of some class or structure.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="serializeMethod">The serialize method.</param>
public YamlMemberAttribute(string name, SerializeMemberMode serializeMethod)
{
this.name = name;
this.serializeMethod = serializeMethod;
}
/// <summary>
/// Specify the way to store a property or field of some class or structure.
/// </summary>
/// <param name="serializeMethod">The serialize method.</param>
public YamlMemberAttribute(SerializeMemberMode serializeMethod)
{
this.serializeMethod = serializeMethod;
}
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
public string Name
{
get { return name; }
}
/// <summary>
/// Gets the serialize method1.
/// </summary>
/// <value>The serialize method1.</value>
public SerializeMemberMode SerializeMethod
{
get { return serializeMethod; }
}
}
}

Просмотреть файл

@ -0,0 +1,36 @@
namespace YamlDotNet.Serialization
{
/// <summary>
/// <para>Specify the way to store a property or field of some class or structure.</para>
/// <para>See <see cref="Serializer"/> for detail.</para>
/// </summary>
public enum SerializeMemberMode
{
/// <summary>
/// The property / field will not be stored.
/// </summary>
Never,
/// <summary>
/// When restored, new object is created by using the parameters in
/// the YAML data and assigned to the property / field. When the
/// property / filed is writeable, this is the default.
/// </summary>
Assign,
/// <summary>
/// Only valid for a property / field that has a class or struct type.
/// When restored, instead of recreating the whole class or struct,
/// the members are independently restored. When the property / field
/// is not writeable this is the default.
/// </summary>
Content,
/// <summary>
/// Only valid for a property / field that has an array type of a
/// some value type. The content of the array is stored in a binary
/// format encoded in base64 style.
/// </summary>
Binary
}
}

Просмотреть файл

@ -0,0 +1,46 @@
using System.IO;
namespace YamlDotNet.Serialization
{
public class YamlSerializer
{
private readonly YamlSerializerSettings settings;
internal readonly TagRegistry TagRegistry;
public YamlSerializer() : this(null)
{
}
public YamlSerializerSettings Settings { get { return settings; } }
public YamlSerializer(YamlSerializerSettings settings)
{
this.settings = settings ?? new YamlSerializerSettings();
TagRegistry = new TagRegistry(Settings);
}
public void Serialize(Stream stream, object value)
{
var context = new SerializerContext(this);
var writer = CreateEmitter(stream, context);
context.Writer = writer;
}
private IEventEmitter CreateEmitter(Stream stream, SerializerContext context)
{
return CreateEmitter(new Emitter(new StreamWriter(stream)), context);
}
private IEventEmitter CreateEmitter(IEmitter emitter, SerializerContext context)
{
var writer = new WriterEventEmitter(emitter, context);
if (settings.EmitJsonComptible)
{
return new JsonEventEmitter(writer);
}
return writer;
}
}
}

Просмотреть файл

@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace YamlDotNet.Serialization
{
/// <summary>
/// Settings used to configure serialization.
/// </summary>
public class YamlSerializerSettings
{
internal readonly Dictionary<string, Type> TagToType = new Dictionary<string, Type>();
internal readonly Dictionary<Type, string> TypeToTag = new Dictionary<Type, string>();
private IAttributeRegistry attributeRegistry;
private ITypeDescriptorFactory typeDescriptorFactory;
private string prefixForItems;
/// <summary>
/// Initializes a new instance of the <see cref="YamlSerializerSettings"/> class.
/// </summary>
public YamlSerializerSettings()
{
SortKeyForMapping = true;
EmitJsonComptible = false;
EmitCapacityForList = false;
PrefixForItems = "~Items";
AttributeRegistry = new DefaultAttributeRegistry();
TypeDescriptorFactory = new DefaultDescriptorFactory(this);
}
/// <summary>
/// Gets or sets a value indicating whether to enable sorting keys for YAML mapping. Default is true. See remarks.
/// </summary>
/// <value><c>true</c> to enable sorting keys for YAML mapping; otherwise, <c>false</c>.</value>
/// <remarks>
/// When storing a YAML document, It can be important to keep the same order for key mapping in order to keep
/// a YAML document versionable/diffable.
/// </remarks>
public bool SortKeyForMapping { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to emit json comptible YAML.
/// </summary>
/// <value><c>true</c> if to emit json comptible YAML; otherwise, <c>false</c>.</value>
public bool EmitJsonComptible { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the property <see cref="System.Collections.IList.Capacity"/> should be emitted. Default is false.
/// </summary>
/// <value><c>true</c> if the property <see cref="System.Collections.IList.Capacity"/> should be emitted; otherwise, <c>false</c>.</value>
public bool EmitCapacityForList { get; set; }
public string PrefixForItems
{
get { return prefixForItems; }
set
{
// TODO check prefix for items
prefixForItems = value;
}
}
/// <summary>
/// Gets or sets the attribute registry.
/// </summary>
/// <value>The attribute registry.</value>
public IAttributeRegistry AttributeRegistry
{
get { return attributeRegistry; }
set
{
if (value == null) throw new ArgumentNullException("value");
attributeRegistry = value;
}
}
/// <summary>
/// Gets or sets the type descriptor factory used when trying to find a <see cref="ITypeDescriptor"/>.
/// </summary>
/// <value>The type descriptor factory.</value>
/// <exception cref="System.ArgumentNullException">value</exception>
public ITypeDescriptorFactory TypeDescriptorFactory
{
get { return typeDescriptorFactory; }
set
{
if (value == null) throw new ArgumentNullException("value");
typeDescriptorFactory = value;
}
}
public void RegisterTagAlias(string tagName, Type type)
{
TagToType[tagName] = type;
TypeToTag[type] = tagName;
}
public List<Assembly> LookupAssemblies { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,28 @@
using System;
namespace YamlDotNet.Serialization
{
/// <summary>
/// An attribute to associate a tag with a particular type.
/// </summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Enum)]
public class YamlTagAttribute : Attribute
{
private readonly string tag;
/// <summary>
/// Initializes a new instance of the <see cref="YamlTagAttribute"/> class.
/// </summary>
/// <param name="tag">The tag.</param>
public YamlTagAttribute(string tag)
{
this.tag = tag;
}
/// <summary>
/// Gets the tag.
/// </summary>
/// <value>The tag.</value>
public string Tag { get { return tag; } }
}
}

Просмотреть файл

@ -0,0 +1,20 @@
namespace YamlDotNet
{
/// <summary>
/// Add extensions methods to <see cref="System.String"/>.
/// </summary>
internal static class StringExtension
{
/// <summary>
/// Expression of string.Format(this, arg1, arg2, ...)
/// </summary>
/// <param name="format">The format string.</param>
/// <param name="args">The arguments.</param>
/// <returns>A formatted string.</returns>
/// <see cref="string.Format(System.IFormatProvider,string,object[])"/>
public static string DoFormat(this string format, params object[] args)
{
return string.Format(format, args);
}
}
}

Просмотреть файл

@ -0,0 +1,171 @@
using System;
using System.Reflection;
namespace YamlDotNet
{
internal static class TypeExtensions
{
public static Type GetInterface(this Type type, Type lookInterfaceType)
{
if (lookInterfaceType.IsGenericTypeDefinition)
{
foreach (var interfaceType in type.GetInterfaces())
{
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == lookInterfaceType)
{
return interfaceType;
}
}
}
else
{
foreach (var interfaceType in type.GetInterfaces())
{
if (interfaceType == lookInterfaceType)
{
return interfaceType;
}
}
}
return null;
}
/// <summary>
/// Check if the type is a ValueType and does not contain any non ValueType members.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static bool IsPureValueType(this Type type)
{
if (type == null)
return false;
if (type == typeof(IntPtr))
return false;
if (type.IsPrimitive)
return true;
if (type.IsEnum)
return true;
if (!type.IsValueType)
return false;
// struct
foreach (var f in type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance))
if (!IsPureValueType(f.FieldType))
return false;
return true;
}
/// <summary>
/// Returnes true if the specified <paramref name="type"/> is a struct type.
/// </summary>
/// <param name="type"><see cref="Type"/> to be analyzed.</param>
/// <returns>true if the specified <paramref name="type"/> is a struct type; otehrwise false.</returns>
public static bool IsStruct(this Type type)
{
return type != null && type.IsValueType && !type.IsPrimitive;
}
/// <summary>
/// Return if an object is a numeric value.
/// </summary>
/// <param name="obj">Any object to be tested.</param>
/// <returns>True if object is a numeric value.</returns>
public static bool IsNumeric(this Type type)
{
return type != null && (type == typeof(sbyte) || type == typeof(short) || type == typeof(int) || type == typeof(long) ||
type == typeof(byte) || type == typeof(ushort) || type == typeof(uint) || type == typeof(ulong) ||
type == typeof(float) || type == typeof(double) || type == typeof(decimal));
}
/// <summary>
/// Compare two objects to see if they are equal or not. Null is acceptable.
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static bool AreEqual(object a, object b)
{
if (a == null)
return b == null;
if (b == null)
return false;
return a.Equals(b) || b.Equals(a);
}
/// <summary>
/// Cast an object to a specified numeric type.
/// </summary>
/// <param name="obj">Any object</param>
/// <param name="type">Numric type</param>
/// <returns>Numeric value or null if the object is not a numeric value.</returns>
public static object CastToNumericType(this Type type, object obj)
{
var doubleValue = CastToDouble(obj);
if (double.IsNaN(doubleValue))
return null;
if (obj is decimal && type == typeof(decimal))
return obj; // do not convert into double
object result = null;
if (type == typeof(sbyte))
result = (sbyte)doubleValue;
if (type == typeof(byte))
result = (byte)doubleValue;
if (type == typeof(short))
result = (short)doubleValue;
if (type == typeof(ushort))
result = (ushort)doubleValue;
if (type == typeof(int))
result = (int)doubleValue;
if (type == typeof(uint))
result = (uint)doubleValue;
if (type == typeof(long))
result = (long)doubleValue;
if (type == typeof(ulong))
result = (ulong)doubleValue;
if (type == typeof(float))
result = (float)doubleValue;
if (type == typeof(double))
result = doubleValue;
if (type == typeof(decimal))
result = (decimal)doubleValue;
return result;
}
/// <summary>
/// Cast boxed numeric value to double
/// </summary>
/// <param name="obj">boxed numeric value</param>
/// <returns>Numeric value in double. Double.Nan if obj is not a numeric value.</returns>
public static double CastToDouble(object obj)
{
var result = double.NaN;
var type = obj != null ? obj.GetType() : null;
if (type == typeof(sbyte))
result = (double)(sbyte)obj;
if (type == typeof(byte))
result = (double)(byte)obj;
if (type == typeof(short))
result = (double)(short)obj;
if (type == typeof(ushort))
result = (double)(ushort)obj;
if (type == typeof(int))
result = (double)(int)obj;
if (type == typeof(uint))
result = (double)(uint)obj;
if (type == typeof(long))
result = (double)(long)obj;
if (type == typeof(ulong))
result = (double)(ulong)obj;
if (type == typeof(float))
result = (double)(float)obj;
if (type == typeof(double))
result = (double)obj;
if (type == typeof(decimal))
result = (double)(decimal)obj;
return result;
}
}
}

Просмотреть файл

@ -84,8 +84,72 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Scanner.cs" />
<Compile Include="SemanticErrorException.cs" />
<Compile Include="Serialization\AnchorNotFoundException.cs" />
<Compile Include="Serialization\ArrayDescriptor.cs" />
<Compile Include="Serialization\CollectionDescriptor.cs" />
<Compile Include="Serialization\DefaultDescriptorFactory.cs" />
<Compile Include="Serialization\DictionaryDescriptor.cs" />
<Compile Include="Serialization\DocumentLoadingState.cs" />
<Compile Include="Serialization\DuplicateAnchorException.cs" />
<Compile Include="Serialization\EmitterState.cs" />
<Compile Include="Serialization\FieldDescriptor.cs" />
<Compile Include="Serialization\IAttributeRegistry.cs" />
<Compile Include="Serialization\IMemberDescriptor.cs" />
<Compile Include="Serialization\ITypeDescriptor.cs" />
<Compile Include="Serialization\ITypeDescriptorFactory.cs" />
<Compile Include="Serialization\IYamlVisitor.cs" />
<Compile Include="Serialization\MemberDescriptorBase.cs" />
<Compile Include="Serialization\ObjectDescriptor.cs" />
<Compile Include="Serialization\Processors\AnchorProcessor.cs" />
<Compile Include="Serialization\ChainedEventEmitter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Serialization\Processors\ChainedProcessor.cs" />
<Compile Include="Serialization\EventInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Serialization\IdentityEqualityComparer.cs" />
<Compile Include="Serialization\IEventEmitter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Serialization\IYamlProcessor.cs" />
<Compile Include="Serialization\IYamlSerializableFactory.cs" />
<Compile Include="Serialization\JsonEventEmitter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Serialization\Processors\DictionaryProcessor.cs" />
<Compile Include="Serialization\Processors\ObjectProcessor.cs" />
<Compile Include="Serialization\PropertyDescriptor.cs" />
<Compile Include="Serialization\SerializerContext.cs" />
<Compile Include="Serialization\DefaultAttributeRegistry.cs" />
<Compile Include="Serialization\TagRegistry.cs" />
<Compile Include="Serialization\TypeAssigningEventEmitter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Serialization\WriterEventEmitter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Serialization\YamlAliasNode.cs" />
<Compile Include="Serialization\YamlDocument.cs" />
<Compile Include="Serialization\YamlFormatter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Serialization\YamlIgnoreAttribute.cs" />
<Compile Include="Serialization\YamlMappingNode.cs" />
<Compile Include="Serialization\YamlMemberAttribute.cs" />
<Compile Include="Serialization\YamlNode.cs" />
<Compile Include="Serialization\YamlNodeIdentityEqualityComparer.cs" />
<Compile Include="Serialization\YamlScalarNode.cs" />
<Compile Include="Serialization\YamlSequenceNode.cs" />
<Compile Include="Serialization\YamlSerializableMethod.cs" />
<Compile Include="Serialization\YamlSerializer.cs" />
<Compile Include="Serialization\YamlSerializerSettings.cs" />
<Compile Include="Serialization\YamlStream.cs" />
<Compile Include="Serialization\YamlTagAttribute.cs" />
<Compile Include="Serialization\YamlVisitor.cs" />
<Compile Include="SimpleKey.cs" />
<Compile Include="SortedDictionary.cs" />
<Compile Include="StringExtensions.cs" />
<Compile Include="StringLookAheadBuffer.cs" />
<Compile Include="SyntaxErrorException.cs" />
<Compile Include="TagDirectiveCollection.cs" />
@ -112,6 +176,7 @@
<Compile Include="Tokens\Token.cs" />
<Compile Include="Tokens\Value.cs" />
<Compile Include="Tokens\VersionDirective.cs" />
<Compile Include="TypeExtensions.cs" />
<Compile Include="Version.cs" />
<Compile Include="YamlException.cs" />
</ItemGroup>