/// <summary> /// Resets state of specified instance fields/auto-properties to their defaults (null for classes, default value for structs). /// If given instance field implements IDisposable interface, it would be disposed before reset. /// /// It is possible to control which fields/auto-properties would be cleaned with hierarchy, visibility and reset options. /// </summary> /// <typeparam name="T">Target type.</typeparam> /// <param name="target">Target instance to be reset.</param> /// <param name="hierarchyOptions">Options controlling which members would be cleaned, depending on which type in type hierarchy they belongs to.</param> /// <param name="visibilityOptions">Options controlling which members would be cleaned, depending on their visibility flags.</param> /// <param name="resetOptions">An additional reset options.</param> public static void ResetInstance <T>(T target, HierarchyOptions hierarchyOptions = HierarchyOptions.All, VisibilityOptions visibilityOptions = VisibilityOptions.All, ResetOptions resetOptions = ResetOptions.None) where T : class { if (target == null) { return; } Debug.WriteLine(string.Format("Resetting instance of: {0}", target.GetType())); foreach (var field in GetAllFields(target, typeof(T), hierarchyOptions) .Where(f => IsApplicable(f, visibilityOptions, resetOptions))) { if ((resetOptions & ResetOptions.DoNotDispose) == 0) { DisposeField(field, target); } ResetField(field, target); } }
public void ResetInstance_should_honor_hierarchy_options(HierarchyOptions hierarchyOptions, bool shouldResetChildren, bool shouldResetThis, bool shouldResetParent) { var text = "abc"; var guid = Guid.NewGuid(); var childDisposable = new Mock <IDisposable>(); var disposable = new Mock <IDisposable>(); var grandChildDisposable = new Mock <IDisposable>(); var grandDisposable = new Mock <IDisposable>(); var parentDisposable = new Mock <IDisposable>(); var instance = new GrandChild { ChildClass = text, ChildDisposable = childDisposable.Object, ChildStruct = guid, Class = text, Disposable = disposable.Object, GrandChildClass = text, GrandChildDisposable = grandChildDisposable.Object, GrandChildStruct = guid, GrandClass = text, GrandDisposable = grandDisposable.Object, GrandStruct = guid, ParentClass = text, ParentDisposable = parentDisposable.Object, ParentStruct = guid, Struct = guid, AbstractProperty = text, CurrentAbstractProperty = text, GrandAbstractProperty = text }; Current current = instance; StateCleaner.ResetInstance(current, hierarchyOptions, VisibilityOptions.Public); Assert.That(instance.GrandChildClass == null, Is.EqualTo(shouldResetChildren)); Assert.That(instance.AbstractProperty == null, Is.EqualTo(shouldResetChildren)); Assert.That(instance.GrandChildStruct == Guid.Empty, Is.EqualTo(shouldResetChildren)); Assert.That(instance.GrandChildDisposable == null, Is.EqualTo(shouldResetChildren)); grandChildDisposable.Verify(d => d.Dispose(), Times.Exactly(shouldResetChildren ? 1 : 0)); Assert.That(instance.ChildClass == null, Is.EqualTo(shouldResetChildren)); Assert.That(instance.ChildStruct == Guid.Empty, Is.EqualTo(shouldResetChildren)); Assert.That(instance.ChildDisposable == null, Is.EqualTo(shouldResetChildren)); childDisposable.Verify(d => d.Dispose(), Times.Exactly(shouldResetChildren ? 1 : 0)); Assert.That(instance.Class == null, Is.EqualTo(shouldResetThis)); Assert.That(instance.CurrentAbstractProperty == null, Is.EqualTo(shouldResetThis)); Assert.That(instance.Struct == Guid.Empty, Is.EqualTo(shouldResetThis)); Assert.That(instance.Disposable == null, Is.EqualTo(shouldResetThis)); disposable.Verify(d => d.Dispose(), Times.Exactly(shouldResetThis ? 1 : 0)); Assert.That(instance.ParentClass == null, Is.EqualTo(shouldResetParent)); Assert.That(instance.ParentStruct == Guid.Empty, Is.EqualTo(shouldResetParent)); Assert.That(instance.ParentDisposable == null, Is.EqualTo(shouldResetParent)); parentDisposable.Verify(d => d.Dispose(), Times.Exactly(shouldResetParent ? 1 : 0)); Assert.That(instance.GrandClass == null, Is.EqualTo(shouldResetParent)); Assert.That(instance.GrandAbstractProperty == null, Is.EqualTo(shouldResetParent)); Assert.That(instance.GrandStruct == Guid.Empty, Is.EqualTo(shouldResetParent)); Assert.That(instance.GrandDisposable == null, Is.EqualTo(shouldResetParent)); grandDisposable.Verify(d => d.Dispose(), Times.Exactly(shouldResetParent ? 1 : 0)); }
private static IEnumerable <FieldInfo> GetAllFields(object target, Type targetType, HierarchyOptions hierarchyOptions) { if (hierarchyOptions == 0) { throw new ArgumentException("HierarchyOptions are not specified."); } var fields = Enumerable.Empty <FieldInfo>(); if (hierarchyOptions.IsSet(HierarchyOptions.Descendant)) { fields = fields.Concat(GetAllFields(target.GetType(), targetType)); } if (hierarchyOptions.IsSet(HierarchyOptions.Declared)) { fields = fields.Concat(GetAllFields(targetType, targetType.BaseType)); } if (hierarchyOptions.IsSet(HierarchyOptions.Inherited)) { fields = fields.Concat(GetAllFields(targetType.BaseType, null)); } return(fields); }