using ANX.Framework.Content.Pipeline.Helpers; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; namespace ANX.Framework.Content.Pipeline.Serialization.Intermediate { internal abstract class ReflectiveSerializerMemberHelper { private ContentTypeSerializer typeSerializer; private ContentSerializerAttribute formatAttribute; private IntermediateSerializer serializer; private MemberInfo memberInfo; private Type memberType; public ReflectiveSerializerMemberHelper(IntermediateSerializer serializer, MemberInfo memberInfo, Type memberType) { this.serializer = serializer; this.memberInfo = memberInfo; this.memberType = memberType; } public virtual void Initialize() { this.typeSerializer = serializer.GetTypeSerializer(memberType); formatAttribute = Attribute.GetCustomAttribute(memberInfo, typeof(ContentSerializerAttribute)) as ContentSerializerAttribute; if (formatAttribute == null) { this.formatAttribute = new ContentSerializerAttribute(); this.formatAttribute.ElementName = memberInfo.Name; } else if (this.formatAttribute.ElementName == null) { this.formatAttribute = this.formatAttribute.Clone(); this.formatAttribute.ElementName = memberInfo.Name; } } public abstract object GetValue(object instance); public abstract void SetValue(object instance, object value); public abstract bool CanSetValue(); public abstract bool ShouldSerialize(Type declaringType); public void Serialize(IntermediateWriter output, object parentInstance) { object value = this.GetValue(parentInstance); if (value == null && !this.formatAttribute.AllowNull) throw new InvalidOperationException(string.Format("XML element \"{0}\" is not allowed to be null.", this.formatAttribute.ElementName)); if (this.formatAttribute.Optional) { if (value == null) { return; } if (this.CanSetValue() == false && this.typeSerializer.ObjectIsEmpty(value)) { return; } } if (this.formatAttribute.SharedResource) { output.WriteSharedResource(value, this.formatAttribute); } else { output.WriteObject(value, this.formatAttribute, this.typeSerializer); } } public void Deserialize(IntermediateReader input, object parentInstance) { if (!this.formatAttribute.FlattenContent) { if (this.formatAttribute.Optional) { if (!input.Xml.CheckForElement(this.formatAttribute.ElementName)) { return; } } else { input.Xml.MoveToContent(); } } if (this.formatAttribute.SharedResource) { this.DeserializeSharedResource(input, parentInstance); } else { this.DeserializeRegularObject(input, parentInstance); } } private void DeserializeRegularObject(IntermediateReader input, object parentInstance) { if (this.CanSetValue()) { object value = input.ReadObject(this.formatAttribute, this.typeSerializer); this.SetValue(parentInstance, value); } else { object obj = this.GetValue(parentInstance); if (obj == null) throw ExceptionHelper.CreateInvalidContentException(input.Xml, input.BasePath, null, string.Format("Cannot deserialize XML element \"{0}\" because this member is both null and read-only.", this.formatAttribute.ElementName)); input.ReadObject(this.formatAttribute, this.typeSerializer, obj); } } private void DeserializeSharedResource(IntermediateReader input, object parentInstance) { if (this.CanSetValue() == false) throw new InvalidOperationException("Members marked with ContentSerializerAttribute.SharedResource cannot be read-only."); input.ReadSharedResource(this.formatAttribute, (object value) => { if (value == null || !this.typeSerializer.TargetType.IsAssignableFrom(value.GetType())) { throw ExceptionHelper.CreateInvalidContentException(input.Xml, input.BasePath, null, string.Format("XML specifies invalid type for shared resource. Expecting a subclass of \"{0}\", but XML contains \"{1}\".", this.typeSerializer.TargetType, value.GetType() )); } this.SetValue(parentInstance, value); }); } public bool ObjectIsEmpty(object parent) { object obj = this.GetValue(parent); return obj == null || this.typeSerializer.ObjectIsEmpty(obj); } protected static bool IsSharedResource(MemberInfo memberInfo) { Attribute customAttribute = Attribute.GetCustomAttribute(memberInfo, typeof(ContentSerializerAttribute)); return customAttribute != null && ((ContentSerializerAttribute)customAttribute).SharedResource; } } }