x) ser/deser of collections
This commit is contained in:
parent
79b42b723e
commit
14615e95e0
@ -13,6 +13,7 @@ using System.Diagnostics;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using static System.Net.WebRequestMethods;
|
using static System.Net.WebRequestMethods;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -102,6 +103,9 @@ namespace lib
|
|||||||
}
|
}
|
||||||
|
|
||||||
public record struct TypeProxy( Func<object, string> ser, Func<string, string, object> des );
|
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 class XmlFormatter2Cfg: Config
|
||||||
{
|
{
|
||||||
@ -114,6 +118,9 @@ namespace lib
|
|||||||
|
|
||||||
public Dictionary<Type, TypeProxy> TypeProxy = new();
|
public Dictionary<Type, TypeProxy> TypeProxy = new();
|
||||||
|
|
||||||
|
//public Dictionary<Type, CollectionCreator> CollectionCreator = new();
|
||||||
|
|
||||||
|
|
||||||
public Types TypesDefault = Types.Fields;
|
public Types TypesDefault = Types.Fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,34 +249,55 @@ namespace lib
|
|||||||
return Deserialize( elem, null, type, null );
|
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*/ )
|
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 )
|
if( typeCode != TypeCode.Object )
|
||||||
{
|
|
||||||
return DeserializeConcrete( elem, mi, type );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( !type.IsArray )
|
|
||||||
{
|
{
|
||||||
object obj = DeserializeObject(elem, mi, type, existing);
|
return DeserializeConcrete( elem, mi, type );
|
||||||
|
|
||||||
if( obj is I_Serialize )
|
|
||||||
{
|
|
||||||
var iser = obj as I_Serialize;
|
|
||||||
|
|
||||||
iser.OnDeserialize( null );
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
}
|
||||||
else
|
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];
|
Type[] mm_types = new Type[1];
|
||||||
@ -472,11 +500,13 @@ namespace lib
|
|||||||
|
|
||||||
var dontAtt = childFi.GetCustomAttributes<lib.Dont>();
|
var dontAtt = childFi.GetCustomAttributes<lib.Dont>();
|
||||||
|
|
||||||
|
string propName = "";
|
||||||
|
|
||||||
if( name.StartsWith( "<" ) && name.EndsWith( "BackingField" ) )
|
if( name.StartsWith( "<" ) && name.EndsWith( "BackingField" ) )
|
||||||
{
|
{
|
||||||
var gtIndex = name.IndexOf( '>' );
|
var gtIndex = name.IndexOf( '>' );
|
||||||
|
|
||||||
var propName = name.Substring( 1, gtIndex - 1 );
|
propName = name.Substring( 1, gtIndex - 1 );
|
||||||
|
|
||||||
var propInfo = narrowType.GetProperty( propName );
|
var propInfo = narrowType.GetProperty( propName );
|
||||||
|
|
||||||
@ -496,6 +526,7 @@ namespace lib
|
|||||||
if (FilterField(filterFields, doImpls, whitelistFields, childFi as MemberInfo, name)) continue;
|
if (FilterField(filterFields, doImpls, whitelistFields, childFi as MemberInfo, name)) continue;
|
||||||
|
|
||||||
XmlElement childElem = getNamedChild(allChildren, name);
|
XmlElement childElem = getNamedChild(allChildren, name);
|
||||||
|
if( childElem == null && !string.IsNullOrEmpty( propName ) ) childElem = getNamedChild( allChildren, propName );
|
||||||
|
|
||||||
if (childElem != null)
|
if (childElem != null)
|
||||||
{
|
{
|
||||||
@ -609,6 +640,114 @@ namespace lib
|
|||||||
return list;
|
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 )
|
private object DeserializeArray( XmlElement elem, MemberInfo mi, Type type )
|
||||||
{
|
{
|
||||||
Type typeElem = type.GetElementType();
|
Type typeElem = type.GetElementType();
|
||||||
@ -848,7 +987,14 @@ namespace lib
|
|||||||
{
|
{
|
||||||
if( !type.IsArray )
|
if( !type.IsArray )
|
||||||
{
|
{
|
||||||
SerializeObject( writer, mi, root, depth );
|
if( IsEnumerable( type ))
|
||||||
|
{
|
||||||
|
SerializeCollection( writer, mi, root, depth );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SerializeObject( writer, mi, root, depth );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -874,6 +1020,44 @@ namespace lib
|
|||||||
writer.WriteAttributeString( "v", root.ToString() );
|
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 )
|
private void SerializeObject( XmlWriter writer, MemberInfo mi, object root, int depth )
|
||||||
{
|
{
|
||||||
writer.WriteAttributeString( "_.t", getTypeName( root.GetType() ) );
|
writer.WriteAttributeString( "_.t", getTypeName( root.GetType() ) );
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user