123 lines
No EOL
5 KiB
C#
123 lines
No EOL
5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using JD.Core;
|
|
|
|
namespace JD.Serialization
|
|
{
|
|
/// <summary>
|
|
/// Helper methods for the serializers.
|
|
/// </summary>
|
|
public static class SerializationExtensions
|
|
{
|
|
/// <summary>
|
|
/// Contains a cached default instantiation of each Type. It allows to test for default values.
|
|
/// </summary>
|
|
private static readonly Cache<Type, object> _defaultInstances = new Cache<Type, object>();
|
|
|
|
/// <summary>
|
|
/// Caches the serializable fields of given type.
|
|
/// </summary>
|
|
private static readonly Cache<object, IEnumerable<PropertyInfo>> _serializableFields = new Cache<object, IEnumerable<PropertyInfo>>();
|
|
|
|
/// <summary>
|
|
/// Caches the attributes of a property.
|
|
/// </summary>
|
|
private static readonly Cache<object, System.Attribute> _propertyAttributes = new Cache<object, System.Attribute>();
|
|
|
|
public static TAttribtue GetAttribute<TAttribtue>(this PropertyInfo property)
|
|
where TAttribtue : System.Attribute
|
|
{
|
|
return (TAttribtue) _propertyAttributes.GetOrCompute(new {property, attributeType = typeof (TAttribtue)}, toCompute =>
|
|
{
|
|
return property.GetCustomAttributes(typeof (TAttribtue), false).OfType<TAttribtue>().FirstOrDefault();
|
|
});
|
|
}
|
|
|
|
public static bool IsOptional(this PropertyInfo property)
|
|
{
|
|
return property.GetAttribute<UAFOptionnalAttribute>() != null;
|
|
}
|
|
|
|
public static bool IsFactoryType(this PropertyInfo property, Type type)
|
|
{
|
|
return ObjectFactory.isTypeInAnyFactory(type) || (property != null && property.GetAttribute<UAFFactoryAttribute>() != null);
|
|
}
|
|
|
|
public static IEnumerable<PropertyInfo> SerializableFields(this Type type, SerializationFlags flags = SerializationFlags.Default, bool includeSpecialFields = false)
|
|
{
|
|
// Manipulation reflection can reduce perf and we are sure this info never changes, this caches the result.
|
|
return _serializableFields.GetOrCompute(new { type, flags, includeSpecialFields }, arguments => ComputeSerializableFields(type, flags, includeSpecialFields));
|
|
}
|
|
|
|
private static IEnumerable<PropertyInfo> ComputeSerializableFields(Type type, SerializationFlags flags, bool includeSpecialFields = false)
|
|
{
|
|
// We reverse the member to try to reproduce the engine order (base classes first) so that the files does not change a lot.
|
|
// when they are saved by the tool or by the engine.
|
|
|
|
var result = new List<PropertyInfo>();
|
|
while (type != null)
|
|
{
|
|
PropertyInfo[] properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
|
|
|
|
result.InsertRange(0, properties.Where(field => field.IsSerializable(flags, includeSpecialFields)));
|
|
type = type.BaseType;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static bool IsSerializable(this PropertyInfo property, SerializationFlags flags = SerializationFlags.Default, bool includeSpecialFields = false)
|
|
{
|
|
var attribute = property.GetAttribute<UAFSerializableAttribute>();
|
|
bool isSerializable = attribute != null && (attribute.Flags & flags) != 0;
|
|
|
|
if (!isSerializable && includeSpecialFields)
|
|
{
|
|
return property.GetAttribute<UafSerializableSpecialAttribute>() != null;
|
|
}
|
|
|
|
return isSerializable;
|
|
}
|
|
|
|
#region Default Values
|
|
|
|
/// <summary>
|
|
/// True if the property value is the default value of the serializable field.
|
|
/// </summary>
|
|
public static bool HasDefaultValue(this object instance, PropertyInfo property)
|
|
{
|
|
object propertyValue = property.GetValue(instance, null);
|
|
object defaultValue = property.GetValue(DefaultInstance(instance.GetType()), null);
|
|
|
|
if (propertyValue is IUAFCollection)
|
|
{
|
|
return ((IUAFCollection)propertyValue).Count == 0;
|
|
}
|
|
if (defaultValue != null && propertyValue != null &&
|
|
defaultValue.GetType() == propertyValue.GetType() &&
|
|
!BasicTypeList.IsBasicType(propertyValue.GetType()))
|
|
{
|
|
return IsDefaultClass(propertyValue);
|
|
}
|
|
|
|
return Equals(propertyValue, defaultValue);
|
|
}
|
|
|
|
private static object DefaultInstance(this Type type)
|
|
{
|
|
return _defaultInstances.GetOrCompute(type, Activator.CreateInstance);
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if the class is not modified.
|
|
/// </summary>
|
|
/// <remarks>This allows to skip non modified fields when writing a lua file.</remarks>
|
|
private static bool IsDefaultClass(this object instance)
|
|
{
|
|
return instance.GetType().SerializableFields().All(instance.HasDefaultValue);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |