55using System . Numerics ;
66using System . IO ;
77using System . Diagnostics ;
8+ using System . Reflection ;
9+ using System . Runtime . CompilerServices ;
810
911namespace Datamodel . Codecs
1012{
@@ -344,8 +346,15 @@ object ReadValue(Datamodel dm, Type type, bool raw_string)
344346 throw new ArgumentException ( type == null ? "No type provided to GetValue()" : "Cannot read value of type " + type . Name ) ;
345347 }
346348
347- public Datamodel Decode ( string encoding , int encoding_version , string format , int format_version , Stream stream , DeferredMode defer_mode )
349+ public Datamodel Decode ( string encoding , int encoding_version , string format , int format_version , Stream stream , DeferredMode defer_mode , Assembly callingAssembly , bool attemptReflection )
348350 {
351+ Dictionary < string , Type > callingTypes = new ( ) ;
352+
353+ foreach ( var classType in callingAssembly . DefinedTypes )
354+ {
355+ callingTypes . Add ( classType . Name , classType ) ;
356+ }
357+
349358 stream . Seek ( 0 , SeekOrigin . Begin ) ;
350359 while ( true )
351360 {
@@ -383,7 +392,39 @@ public Datamodel Decode(string encoding, int encoding_version, string format, in
383392 var id_bits = Reader . ReadBytes ( 16 ) ;
384393 var id = new Guid ( BitConverter . IsLittleEndian ? id_bits : id_bits . Reverse ( ) . ToArray ( ) ) ;
385394
386- var elem = new Element ( dm , name , id , type ) ;
395+ Element ? elem = null ;
396+ var matchedType = callingTypes . TryGetValue ( type , out var classType ) ;
397+
398+ if ( matchedType )
399+ {
400+ var isElementDerived = IsElementDerived ( classType ) ;
401+ if ( isElementDerived && classType . Name == type )
402+ {
403+ Type derivedType = classType ;
404+
405+ ConstructorInfo ? constructor = typeof ( Element ) . GetConstructor (
406+ BindingFlags . Instance | BindingFlags . Public | BindingFlags . NonPublic ,
407+ null ,
408+ new Type [ ] { typeof ( Datamodel ) , typeof ( string ) , typeof ( Guid ) , typeof ( string ) } ,
409+ null
410+ ) ;
411+
412+ if ( constructor == null )
413+ {
414+ throw new InvalidOperationException ( "Failed to get constructor while attemption reflection based deserialisation" ) ;
415+ }
416+
417+ object uninitializedObject = RuntimeHelpers . GetUninitializedObject ( derivedType ) ;
418+ constructor . Invoke ( uninitializedObject , new object [ ] { dm , name , id , type } ) ;
419+
420+ elem = ( Element ? ) uninitializedObject ;
421+ }
422+ }
423+
424+ if ( elem == null )
425+ {
426+ elem = new Element ( dm , name , id , type ) ;
427+ }
387428 }
388429
389430 // read attributes (or not, if we're deferred)
@@ -396,8 +437,7 @@ public Datamodel Decode(string encoding, int encoding_version, string format, in
396437 foreach ( var i in Enumerable . Range ( 0 , num_attrs ) )
397438 {
398439 var name = StringDict . ReadString ( ) ;
399-
400- if ( defer_mode == DeferredMode . Automatic )
440+ if ( defer_mode == DeferredMode . Automatic && attemptReflection == false )
401441 {
402442 CodecUtilities . AddDeferredAttribute ( elem , name , Reader . BaseStream . Position ) ;
403443 SkipAttribute ( ) ;
@@ -408,6 +448,7 @@ public Datamodel Decode(string encoding, int encoding_version, string format, in
408448 }
409449 }
410450 }
451+
411452 return dm ;
412453 }
413454
@@ -762,6 +803,28 @@ void WriteAttribute(object value, bool in_array)
762803 }
763804 }
764805
806+ bool IsElementDerived ( Type type )
807+ {
808+ var elementType = typeof ( Element ) ;
809+
810+ while ( type . BaseType != elementType )
811+ {
812+ var baseType = type . BaseType ;
813+
814+ if ( baseType != null )
815+ {
816+ type = baseType ;
817+ }
818+ else
819+ {
820+ return type == elementType ? true : false ;
821+ }
822+
823+ }
824+
825+ return type . BaseType == elementType ? true : false ;
826+ }
827+
765828 class DmxBinaryWriter : BinaryWriter
766829 {
767830 public DmxBinaryWriter ( Stream output )
0 commit comments