EQXSerializer(Type type) { m_type = type; m_dynamicType = DynamicType.GetDynamicType(m_type); // build the functions here to pay the cost up front, once per type, instead of at runtime // whenever an element is processed ReaderDelegate readAttributes = (XPathNavigator reader, ref object target) => { }; ReaderDelegate readElements = (XPathNavigator reader, ref object target) => { }; ReaderDelegate readArrays = (XPathNavigator reader, ref object target) => { }; WriterDelegate writeAttributes = (XElement result, ref object target) => { }; WriterDelegate writeElements = (XElement result, ref object target) => { }; WriterDelegate writeArrays = (XElement result, ref object target) => { }; for (int i = 0; i < m_dynamicType.Members.Count; i++) { // this goofy setup is to prevent the dynamic methods from acessing the wrong member int temp = i; DynamicMember member = m_dynamicType.Members[temp]; object[] attributes = member.MemberInfo.GetCustomAttributes(false); EqXAttributeAttribute eqxAttribute = null; EqXElementAttribute eqxElement = null; EqXArrayAttribute eqxArray = null; DefaultValueAttribute defaultValue = null; foreach (object attr in attributes) { eqxAttribute = eqxAttribute ?? attr as EqXAttributeAttribute; eqxElement = eqxElement ?? attr as EqXElementAttribute; eqxArray = eqxArray ?? attr as EqXArrayAttribute; defaultValue = defaultValue ?? attr as DefaultValueAttribute; } // count how many of the eqx attributes are present int eqxCount = ((eqxAttribute != null) ? 1 : 0) + ((eqxElement != null) ? 1 : 0) + ((eqxArray != null) ? 1 : 0); #if DEBUG // check how many attributes are present in debug builds to sort out ambiguity if (eqxCount > 1) Trace.TraceWarning(TooManyAttributes, m_type.Name, member.MemberName); #endif // don't process members that aren't marked if (eqxCount < 1) continue; #if DEBUG if (!member.CanWrite && !member.CanRead) { Trace.TraceWarning("'{0}.{1}' has no way to be read or written, skipping it.", m_type.Name, member.MemberName); continue; } else if (!member.CanRead) { Trace.TraceWarning("'{0}.{1}' marked for serialization but can not be read, skipping it.", m_type.Name, member.MemberName); continue; } else if (!member.CanWrite) { Trace.TraceWarning("'{0}.{1}' marked for serialization but can not be written, skipping it.", m_type.Name, member.MemberName); continue; } #endif // find the default value for the member object dvalue = null; if (defaultValue != null) dvalue = defaultValue.Value; if (member.MemberType.IsValueType && dvalue == null) dvalue = Activator.CreateInstance(member.MemberType); if (eqxAttribute != null) { if (!member.MemberType.IsPrimitive && member.MemberType != typeof(string)) throw new InvalidOperationException(string.Format(OnlyPrimitivesXmlAttributes, m_type.Name, member.MemberName)); string name = eqxAttribute.Name ?? member.MemberName; readAttributes += ReadPrimitive(member, string.Concat("@", name), dvalue); writeAttributes += WritePrimitiveAttribute(member, name, dvalue, eqxAttribute.AlwaysWrite); } else if (eqxElement != null) { string name = eqxElement.Name ?? member.MemberName; if (member.MemberType.IsComplex() && member.MemberType != typeof(string)) { readElements += ReadComplex(member, name, dvalue); writeElements += WriteComplexElement(member, name, dvalue, eqxElement.AlwaysWrite); } else { readElements += ReadPrimitive(member, name, dvalue); writeElements += WritePrimitiveElement(member, name, dvalue, eqxElement.AlwaysWrite); } } else if (eqxArray != null) { string name = eqxArray.Name ?? member.MemberName; readElements += ReadArray(member, name, eqxArray.ItemName, dvalue); writeElements += WriteArray(member, name, eqxArray.ItemName, dvalue, eqxArray.AlwaysWrite); } } m_reader = (XPathNavigator navigator, ref object target) => { if (target == null) target = m_dynamicType.CreateInstance(); if (navigator.HasAttributes) readAttributes(navigator, ref target); if (navigator.HasChildren) { readElements(navigator, ref target); readArrays(navigator, ref target); } }; m_writer = (XElement result, ref object target) => { if (target != null) { writeAttributes(result, ref target); writeElements(result, ref target); writeArrays(result, ref target); } }; }