@@ -484,5 +484,121 @@ protected override void DisposeManaged()
484484 public static DelayedDestructionObject GetObject ( IntPtr handle , bool owns = true ) =>
485485 GetOrAddObject ( handle , owns , ( h , o ) => new DelayedDestructionObject ( h , o ) ) ;
486486 }
487+
488+ [ SkippableFact ]
489+ public void ManagedObjectsAreDisposedBeforeNative ( )
490+ {
491+ var parent1 = ParentChildWorld . GetParent ( "Root" ) ;
492+ var child1 = parent1 . Child ;
493+
494+ parent1 . Dispose ( ) ;
495+
496+ var unownedParent = ParentChildWorld . DisposeUnownedManagedParent ;
497+ var unownedChild = ParentChildWorld . DisposeUnownedManagedChild ;
498+
499+ var managedParent = ParentChildWorld . DisposeManagedParent ;
500+ var managedChild = ParentChildWorld . DisposeManagedChild ;
501+
502+ var nativeParent = ParentChildWorld . DisposeNativeParent ;
503+ var nativeChild = ParentChildWorld . DisposeNativeChild ;
504+
505+ Assert . True ( child1 . IsDisposed ) ;
506+ Assert . True ( parent1 . IsDisposed ) ;
507+
508+ Assert . Equal ( "DisposeUnownedManaged" , unownedParent . State ) ;
509+ Assert . Equal ( "DisposeUnownedManaged" , unownedChild . State ) ;
510+
511+ Assert . Equal ( "DisposeUnownedManaged" , managedParent . State ) ;
512+ Assert . Equal ( "DisposeUnownedManaged" , managedChild . State ) ;
513+
514+ Assert . Equal ( "DisposeUnownedManaged" , nativeParent . State ) ;
515+ Assert . Equal ( "DisposeUnownedManaged" , nativeChild . State ) ;
516+
517+ unownedParent . Dispose ( ) ;
518+ managedParent . Dispose ( ) ;
519+ nativeParent . Dispose ( ) ;
520+ }
521+
522+ private static class ParentChildWorld
523+ {
524+ public static readonly IntPtr ParentHandle = GetNextPtr ( ) ;
525+ public static readonly IntPtr ChildHandle = GetNextPtr ( ) ;
526+
527+ public static ParentObject GetParent ( string state ) =>
528+ SKObject . GetOrAddObject ( ParentHandle , ( h , o ) => new ParentObject ( state , h , o ) ) ;
529+
530+ public static ParentObject DisposeManagedParent ;
531+ public static ChildObject DisposeManagedChild ;
532+
533+ public static ParentObject DisposeNativeParent ;
534+ public static ChildObject DisposeNativeChild ;
535+
536+ public static ParentObject DisposeUnownedManagedParent ;
537+ public static ChildObject DisposeUnownedManagedChild ;
538+ }
539+
540+ private class ParentObject : SKObject
541+ {
542+ public ParentObject ( string state , IntPtr handle , bool owns )
543+ : base ( handle , owns )
544+ {
545+ State = state ;
546+ }
547+
548+ public ChildObject Child =>
549+ OwnedBy ( GetOrAddObject ( ParentChildWorld . ChildHandle , false , ( h , o ) => new ChildObject ( State , h , o ) ) , this ) ;
550+
551+ public string State { get ; }
552+
553+ protected override void DisposeUnownedManaged ( )
554+ {
555+ base . DisposeUnownedManaged ( ) ;
556+
557+ if ( State == "Root" )
558+ {
559+ ParentChildWorld . DisposeUnownedManagedParent = ParentChildWorld . GetParent ( "DisposeUnownedManaged" ) ;
560+ ParentChildWorld . DisposeUnownedManagedChild = ParentChildWorld . DisposeUnownedManagedParent . Child ;
561+ }
562+ }
563+
564+ protected override void DisposeManaged ( )
565+ {
566+ base . DisposeManaged ( ) ;
567+
568+ if ( State == "Root" )
569+ {
570+ ParentChildWorld . DisposeManagedParent = ParentChildWorld . GetParent ( "DisposeManaged" ) ;
571+ ParentChildWorld . DisposeManagedChild = ParentChildWorld . DisposeManagedParent . Child ;
572+ }
573+ }
574+
575+ protected override void DisposeNative ( )
576+ {
577+ base . DisposeNative ( ) ;
578+
579+ if ( State == "Root" )
580+ {
581+ ParentChildWorld . DisposeNativeParent = ParentChildWorld . GetParent ( "DisposeNative" ) ;
582+ ParentChildWorld . DisposeNativeChild = ParentChildWorld . DisposeNativeParent . Child ;
583+ }
584+ }
585+
586+ public override string ToString ( ) =>
587+ $ "Parent: { State } ";
588+ }
589+
590+ private class ChildObject : SKObject
591+ {
592+ public ChildObject ( string state , IntPtr handle , bool owns )
593+ : base ( handle , owns )
594+ {
595+ State = state ;
596+ }
597+
598+ public string State { get ; }
599+
600+ public override string ToString ( ) =>
601+ $ "Child: { State } ";
602+ }
487603 }
488604}
0 commit comments