diff --git a/ser/XmlFormatter2.cs b/ser/XmlFormatter2.cs index 74ed4a2..6a26375 100644 --- a/ser/XmlFormatter2.cs +++ b/ser/XmlFormatter2.cs @@ -13,6 +13,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; using static System.Net.WebRequestMethods; using System.Linq; +using System.Collections.Immutable; /* @@ -102,6 +103,9 @@ namespace lib } public record struct TypeProxy( Func ser, Func des ); + + //public record struct CollectionCreator( Func FnCreate ); + public class XmlFormatter2Cfg: Config { @@ -114,6 +118,9 @@ namespace lib public Dictionary TypeProxy = new(); + //public Dictionary CollectionCreator = new(); + + public Types TypesDefault = Types.Fields; } @@ -242,34 +249,55 @@ namespace lib return Deserialize( elem, null, type, null ); } + private bool IsEnumerable( Type type ) + { + return type.IsAssignableTo( typeof(IEnumerable) ); + } + private object Deserialize( XmlElement elem, MemberInfo mi, Type type, object existing /*, object enclosing = null*/ ) { - TypeCode typeCode = Type.GetTypeCode(type); + try + { + TypeCode typeCode = Type.GetTypeCode(type); - if( typeCode != TypeCode.Object ) - { - return DeserializeConcrete( elem, mi, type ); - } - else - { - if( !type.IsArray ) + if( typeCode != TypeCode.Object ) { - object obj = DeserializeObject(elem, mi, type, existing); - - if( obj is I_Serialize ) - { - var iser = obj as I_Serialize; - - iser.OnDeserialize( null ); - } - - return obj; + return DeserializeConcrete( elem, mi, type ); } else { - return DeserializeArray( elem, mi, type ); + if( !type.IsArray ) + { + if( IsEnumerable(type) ) + { + return DeserializeCollection( elem, mi, type ); + } + else + { + object obj = DeserializeObject(elem, mi, type, existing); + + if( obj is I_Serialize ) + { + var iser = obj as I_Serialize; + + iser.OnDeserialize( null ); + } + + return obj; + } + } + else + { + return DeserializeArray( elem, mi, type ); + } } } + catch( Exception ex ) + { + log.warn( $"Caught exception fn {mi.Name} type {type.Name} of {ex.Message}" ); + } + + return existing; } Type[] mm_types = new Type[1]; @@ -472,11 +500,13 @@ namespace lib var dontAtt = childFi.GetCustomAttributes(); + string propName = ""; + if( name.StartsWith( "<" ) && name.EndsWith( "BackingField" ) ) { var gtIndex = name.IndexOf( '>' ); - var propName = name.Substring( 1, gtIndex - 1 ); + propName = name.Substring( 1, gtIndex - 1 ); var propInfo = narrowType.GetProperty( propName ); @@ -496,6 +526,7 @@ namespace lib if (FilterField(filterFields, doImpls, whitelistFields, childFi as MemberInfo, name)) continue; XmlElement childElem = getNamedChild(allChildren, name); + if( childElem == null && !string.IsNullOrEmpty( propName ) ) childElem = getNamedChild( allChildren, propName ); if (childElem != null) { @@ -609,6 +640,114 @@ namespace lib return list; } + private object DeserializeCollection( XmlElement elem, MemberInfo mi, Type type ) + { + Type typeElem = typeof(object); + + if( type.GenericTypeArguments.Length == 1 ) + { + typeElem = type.GenericTypeArguments[0]; + } + else if( type.GenericTypeArguments.Length == 2 ) + { + typeElem = typeof(KeyValuePair<,>).MakeGenericType(type.GenericTypeArguments ); + } + + + string refString = elem.GetAttribute("ref"); + int refInt = refString.Length > 0 ? Convert.ToInt32(refString) : -1; + + XmlNodeList arrNodeList = elem.ChildNodes; + + int length = arrNodeList.Count; + + Array arr = createArray(typeElem, refInt, length); + + for( int i = 0; i < arr.Length; ++i ) + { + if( arrNodeList.Item( i ) is XmlElement ) + { + XmlElement arrElem = (XmlElement)arrNodeList.Item(i); + + var finalType = typeElem; + if (arrElem.HasAttribute("_.t")) + { + var typename = arrElem.GetAttribute("_.t"); + finalType = FindType(typename); + + if (finalType == null) + finalType = typeElem; + } + + arr.SetValue( Deserialize( arrElem, mi, finalType, null), i ); + } + } + + var listType = (typeof(List<>)).MakeGenericType( typeElem ); + IList list = Activator.CreateInstance( listType ) as IList; + + foreach( var a in arr ) + { + list.Add( a ); + } + + MethodInfo ?toMeth = null; + + var typeGen = Type.MakeGenericSignatureType( type ); + + if( type == typeof(ImmutableArray<>).MakeGenericType( typeElem ) ) + { + var genMeth = GetType().GetMethod("MakeImmutableArray", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic ); + toMeth = genMeth.MakeGenericMethod( typeElem ); + } + else if( type == typeof(ImmutableDictionary<,>).MakeGenericType( typeElem.GenericTypeArguments ) ) + { + var genMeth = GetType().GetMethod("MakeImmutableDictionary", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic ); + toMeth = genMeth.MakeGenericMethod( typeElem.GenericTypeArguments ); + } + else if( type == typeof(List<>).MakeGenericType( typeElem ) ) + { + var genMeth = GetType().GetMethod("MakeList", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic ); + toMeth = genMeth.MakeGenericMethod( typeElem ); + } + else if( type == typeof(Dictionary<,>).MakeGenericType( typeElem.GenericTypeArguments ) ) + { + var genMeth = GetType().GetMethod("MakeDictionary", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic ); + toMeth = genMeth.MakeGenericMethod( typeElem.GenericTypeArguments ); + } + + + var obj = toMeth?.Invoke( this, new object[1] { list } ); + + return obj; + + } + + private List MakeList( IList list ) + { + return list as List; + } + + private object MakeImmutableArray( List list ) + { + var arr = list.ToImmutableArray(); + return arr; + } + + private object MakeImmutableDictionary( List> list ) + { + var dict = list.ToImmutableDictionary(); + return dict; + } + + + private object MakeDictionary( List> list ) + { + var dict = list.ToDictionary(); + return dict; + } + + private object DeserializeArray( XmlElement elem, MemberInfo mi, Type type ) { Type typeElem = type.GetElementType(); @@ -848,7 +987,14 @@ namespace lib { if( !type.IsArray ) { - SerializeObject( writer, mi, root, depth ); + if( IsEnumerable( type )) + { + SerializeCollection( writer, mi, root, depth ); + } + else + { + SerializeObject( writer, mi, root, depth ); + } } else { @@ -874,6 +1020,44 @@ namespace lib writer.WriteAttributeString( "v", root.ToString() ); } + private void SerializeCollection( XmlWriter writer, MemberInfo mi, object root, int depth ) + { + IEnumerable it = root as IEnumerable; + + //Array arr = (Array)root; + + Type typeElem = it.GetType().GenericTypeArguments[0]; + + Type type = root.GetType(); + + writer.WriteAttributeString( "_.t", getTypeName( type ) ); + + bool first; + + long refInt = m_objectID.GetId(root, out first); + + if( m_cfg.datastructure == Datastructure.Graph ) + { + writer.WriteAttributeString( "ref", refInt.ToString() ); + } + + if( first ) + { + if( m_cfg.datastructure == Datastructure.Graph ) + { + m_alreadySerialized[refInt] = root; + } + + int i = 0; + foreach( var v in it ) + { + Serialize( writer, mi, v, "i" + i.ToString(), depth + 1, false ); + ++i; + } + } + } + + private void SerializeObject( XmlWriter writer, MemberInfo mi, object root, int depth ) { writer.WriteAttributeString( "_.t", getTypeName( root.GetType() ) );