x) ser/deser of collections

This commit is contained in:
Marc Hernandez 2024-04-28 10:59:47 -07:00
parent 79b42b723e
commit 14615e95e0

View File

@ -13,6 +13,7 @@ using System.Diagnostics;
using System.Runtime.InteropServices;
using static System.Net.WebRequestMethods;
using System.Linq;
using System.Collections.Immutable;
/*
@ -103,6 +104,9 @@ namespace lib
public record struct TypeProxy( Func<object, string> ser, Func<string, string, object> des );
//public record struct CollectionCreator( Func<IEnumerable, object> FnCreate );
public class XmlFormatter2Cfg: Config
{
public Datastructure datastructure = Datastructure.Tree;
@ -114,6 +118,9 @@ namespace lib
public Dictionary<Type, TypeProxy> TypeProxy = new();
//public Dictionary<Type, CollectionCreator> CollectionCreator = new();
public Types TypesDefault = Types.Fields;
}
@ -242,7 +249,14 @@ 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*/ )
{
try
{
TypeCode typeCode = Type.GetTypeCode(type);
@ -253,6 +267,12 @@ namespace lib
else
{
if( !type.IsArray )
{
if( IsEnumerable(type) )
{
return DeserializeCollection( elem, mi, type );
}
else
{
object obj = DeserializeObject(elem, mi, type, existing);
@ -265,12 +285,20 @@ namespace lib
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];
private object GetDefault( Type t )
@ -472,11 +500,13 @@ namespace lib
var dontAtt = childFi.GetCustomAttributes<lib.Dont>();
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<T> MakeList<T>( IList list )
{
return list as List<T>;
}
private object MakeImmutableArray<T>( List<T> list )
{
var arr = list.ToImmutableArray();
return arr;
}
private object MakeImmutableDictionary<K,V>( List<KeyValuePair<K,V>> list )
{
var dict = list.ToImmutableDictionary();
return dict;
}
private object MakeDictionary<K,V>( List<KeyValuePair<K,V>> list )
{
var dict = list.ToDictionary();
return dict;
}
private object DeserializeArray( XmlElement elem, MemberInfo mi, Type type )
{
Type typeElem = type.GetElementType();
@ -847,9 +986,16 @@ namespace lib
else
{
if( !type.IsArray )
{
if( IsEnumerable( type ))
{
SerializeCollection( writer, mi, root, depth );
}
else
{
SerializeObject( writer, mi, root, depth );
}
}
else
{
SerializeArray( writer, mi, root, depth );
@ -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() ) );