x) Add Type Proxy for saving and loading objects we dont have control
This commit is contained in:
parent
94ce81da96
commit
5e025284f0
@ -90,6 +90,8 @@ namespace lib
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public record struct TypeProxy( Func<object, string> ser, Func<string, string, object> des );
|
||||||
|
|
||||||
public class XmlFormatter2Cfg: Config
|
public class XmlFormatter2Cfg: Config
|
||||||
{
|
{
|
||||||
public Datastructure datastructure = Datastructure.Graph;
|
public Datastructure datastructure = Datastructure.Graph;
|
||||||
@ -98,6 +100,8 @@ namespace lib
|
|||||||
|
|
||||||
public Dictionary<string, List<string>> WLProps = new();
|
public Dictionary<string, List<string>> WLProps = new();
|
||||||
public Dictionary<string, List<string>> WLFields= new();
|
public Dictionary<string, List<string>> WLFields= new();
|
||||||
|
|
||||||
|
public Dictionary<Type, TypeProxy> TypeProxy = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class XmlFormatter2: IFormatter
|
public class XmlFormatter2: IFormatter
|
||||||
@ -129,9 +133,6 @@ namespace lib
|
|||||||
Context = new StreamingContext( StreamingContextStates.All );
|
Context = new StreamingContext( StreamingContextStates.All );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public XmlFormatter2( XmlFormatter2Cfg cfg )
|
public XmlFormatter2( XmlFormatter2Cfg cfg )
|
||||||
{
|
{
|
||||||
Context = new StreamingContext( StreamingContextStates.All );
|
Context = new StreamingContext( StreamingContextStates.All );
|
||||||
@ -141,8 +142,6 @@ namespace lib
|
|||||||
log.warn( $"XML serialization is NOT fast" );
|
log.warn( $"XML serialization is NOT fast" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region Deserialize
|
#region Deserialize
|
||||||
private static FormatterConverter s_conv = new FormatterConverter();
|
private static FormatterConverter s_conv = new FormatterConverter();
|
||||||
|
|
||||||
@ -491,7 +490,7 @@ namespace lib
|
|||||||
|
|
||||||
name = refl.TypeToIdentifier( name );
|
name = refl.TypeToIdentifier( name );
|
||||||
|
|
||||||
if( FilterField( filterFields, doImpls, whitelistFields, childPi as MemberInfo, name ) ) continue;
|
if( FilterField( filterProps, doImpls, whitelistProps, childPi as PropertyInfo, name ) ) continue;
|
||||||
|
|
||||||
XmlElement childElem = getNamedChild( allChildren, name );
|
XmlElement childElem = getNamedChild( allChildren, name );
|
||||||
|
|
||||||
@ -501,7 +500,20 @@ namespace lib
|
|||||||
|
|
||||||
object childObj = Deserialize( childElem, childPi, childPi.PropertyType, existingObj );
|
object childObj = Deserialize( childElem, childPi, childPi.PropertyType, existingObj );
|
||||||
|
|
||||||
childPi.SetValue( obj, childObj );
|
var setMethod = childPi.GetSetMethod();
|
||||||
|
|
||||||
|
if( setMethod != null )
|
||||||
|
{
|
||||||
|
//Object o = Activator.CreateInstance( setMethod.ReflectedType );
|
||||||
|
setMethod.Invoke( obj, new object[]{ childObj } );
|
||||||
|
|
||||||
|
//setMethod.CreateDelegate()
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
childPi.SetValue( obj, childObj );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -540,7 +552,7 @@ namespace lib
|
|||||||
|
|
||||||
int refInt = refString.Length > 0 ? Convert.ToInt32( refString ) : -1;
|
int refInt = refString.Length > 0 ? Convert.ToInt32( refString ) : -1;
|
||||||
|
|
||||||
obj = createObject( finalType, refInt, obj );
|
obj = createObject( elem, finalType, refInt, obj );
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
@ -604,14 +616,14 @@ namespace lib
|
|||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private object createObject( string typename, int refInt, object obj )
|
private object createObject( XmlElement elem, string typename, int refInt, object obj )
|
||||||
{
|
{
|
||||||
Type type = Type.GetType(typename);
|
Type type = Type.GetType(typename);
|
||||||
|
|
||||||
return createObject( type, refInt, obj );
|
return createObject( elem, type, refInt, obj );
|
||||||
}
|
}
|
||||||
|
|
||||||
private object createObject( Type type, int refInt, object existingObj )
|
private object createObject( XmlElement elem, Type type, int refInt, object existingObj )
|
||||||
{
|
{
|
||||||
TypeCode tc = Type.GetTypeCode(type);
|
TypeCode tc = Type.GetTypeCode(type);
|
||||||
|
|
||||||
@ -621,13 +633,60 @@ namespace lib
|
|||||||
return m_alreadySerialized[refInt];
|
return m_alreadySerialized[refInt];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIRST If there is a proxy deserializer, we skip using the existing object.
|
||||||
|
|
||||||
|
var isProxy = elem.HasAttribute( "proxy" );
|
||||||
|
|
||||||
|
if( isProxy )
|
||||||
|
{
|
||||||
|
object obj = null;
|
||||||
|
|
||||||
|
var tryType = type;
|
||||||
|
TypeProxy? proxy = null;
|
||||||
|
|
||||||
|
while( tryType != typeof(object) && obj == null )
|
||||||
|
{
|
||||||
|
//m_cfg.TypeProxy.TryGetValue( )
|
||||||
|
if( m_cfg.TypeProxy.TryGetValue( tryType, out var newProxy ) )
|
||||||
|
{
|
||||||
|
proxy = newProxy;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tryType = tryType.BaseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
var proxyVal = elem.GetAttribute( "proxy" );
|
||||||
|
|
||||||
|
if( proxy.HasValue )
|
||||||
|
{
|
||||||
|
obj = proxy.Value.des( type.Name, proxyVal );
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log.warn( $"Trying to proxy in {elem.Name}, but there is no proxy available. Falling back to regular hydrate/create" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SECOND if we have an existing object there of the same type, replace
|
||||||
|
|
||||||
if( existingObj != null )
|
if( existingObj != null )
|
||||||
{
|
{
|
||||||
var existingObjType = existingObj.GetType();
|
var existingObjType = existingObj.GetType();
|
||||||
|
|
||||||
if( type == existingObjType ) return existingObj;
|
// @@@ GROSS Fix the types so theyre known good.
|
||||||
|
var isSubclass = type.IsSubclassOf( existingObjType ) || existingObjType.IsSubclassOf( type );
|
||||||
|
|
||||||
|
if( isSubclass ) return existingObj;
|
||||||
|
|
||||||
|
// old
|
||||||
|
//if( type == existingObjType ) return existingObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// THIRD create a new object
|
||||||
{
|
{
|
||||||
object obj = null;
|
object obj = null;
|
||||||
|
|
||||||
@ -647,7 +706,6 @@ namespace lib
|
|||||||
{
|
{
|
||||||
log.error( $"Got exception {exInner.Message} trying to make an uninitialized object" );
|
log.error( $"Got exception {exInner.Message} trying to make an uninitialized object" );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( obj == null )
|
if( obj == null )
|
||||||
@ -711,13 +769,11 @@ namespace lib
|
|||||||
return type.FullName; // + ", " + assName;
|
return type.FullName; // + ", " + assName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Serialize( Stream stream, object root )
|
public void Serialize( Stream stream, object root )
|
||||||
{
|
{
|
||||||
Serialize( stream, null, root );
|
Serialize( stream, null, root );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Serialize( Stream stream, MemberInfo mi, object root )
|
public void Serialize( Stream stream, MemberInfo mi, object root )
|
||||||
{
|
{
|
||||||
//lib.log.info( "Serialize( Stream stream, object root ) {0} {1}", m_rndVal, m_alreadySerialized.Count );
|
//lib.log.info( "Serialize( Stream stream, object root ) {0} {1}", m_rndVal, m_alreadySerialized.Count );
|
||||||
@ -798,25 +854,14 @@ namespace lib
|
|||||||
writer.WriteAttributeString( "_.version.", $"{m_cfg.Version}" );
|
writer.WriteAttributeString( "_.version.", $"{m_cfg.Version}" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
if( root is IList )
|
|
||||||
{
|
|
||||||
var list = root as IList;
|
|
||||||
|
|
||||||
Type t = root.GetType();
|
|
||||||
|
|
||||||
Type[] genT = t.GetGenericArguments();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool first;
|
bool first;
|
||||||
|
|
||||||
long refInt = m_objectID.GetId(root, out first);
|
long refInt = m_objectID.GetId(root, out first);
|
||||||
|
|
||||||
|
// @@@@ FIX for proxies.
|
||||||
if( m_cfg.datastructure == Datastructure.Graph )
|
if( m_cfg.datastructure == Datastructure.Graph )
|
||||||
{
|
{
|
||||||
writer.WriteAttributeString( "ref", refInt.ToString() );
|
writer.WriteAttributeString( "ref", refInt.ToString() );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( first )
|
if( first )
|
||||||
@ -828,24 +873,15 @@ namespace lib
|
|||||||
|
|
||||||
Type type = root.GetType();
|
Type type = root.GetType();
|
||||||
|
|
||||||
//var whitelistProp = type.GetCustomAttribute<WhitelistPropsAttribute>();
|
|
||||||
|
|
||||||
//var useWhitelist = whitelistProp != null;
|
|
||||||
|
|
||||||
|
|
||||||
//*
|
//*
|
||||||
Type typeISerializable = typeof(ISerializable);
|
Type typeISerializable = typeof(ISerializable);
|
||||||
|
|
||||||
if( root is ISerializable ) // type.IsSubclassOf( typeISerializable ) )
|
if( root is ISerializable ser )
|
||||||
{
|
{
|
||||||
ISerializable ser = root as ISerializable;
|
|
||||||
|
|
||||||
var serInfo = new SerializationInfo(type, new FormatterConverter());
|
var serInfo = new SerializationInfo(type, new FormatterConverter());
|
||||||
|
|
||||||
ser.GetObjectData( serInfo, Context );
|
ser.GetObjectData( serInfo, Context );
|
||||||
|
|
||||||
//var serEnum = ;
|
|
||||||
|
|
||||||
foreach( var serMember in serInfo )
|
foreach( var serMember in serInfo )
|
||||||
{
|
{
|
||||||
String name = serMember.Name;
|
String name = serMember.Name;
|
||||||
@ -855,11 +891,33 @@ namespace lib
|
|||||||
Serialize( writer, mi, serMember.Value, name, depth, true );
|
Serialize( writer, mi, serMember.Value, name, depth, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
//var sc = new SerializationContext(
|
return;
|
||||||
|
|
||||||
//ser.GetObjectData(
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
{
|
||||||
|
var tryType = type;
|
||||||
|
TypeProxy? proxy = null;
|
||||||
|
|
||||||
|
while( tryType != typeof(object) )
|
||||||
|
{
|
||||||
|
if( m_cfg.TypeProxy.TryGetValue( tryType, out var newProxy ) )
|
||||||
|
{
|
||||||
|
proxy = newProxy;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tryType = tryType.BaseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( proxy.HasValue )
|
||||||
|
{
|
||||||
|
var proxyStr = proxy.Value.ser( root );
|
||||||
|
writer.WriteAttributeString( "proxy", proxyStr );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//*/
|
//*/
|
||||||
{
|
{
|
||||||
bool filterFields, filterProps, doImpls, doFields, doProps;
|
bool filterFields, filterProps, doImpls, doFields, doProps;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user