Skip to content

Instantly share code, notes, and snippets.

@ceddlyburge
Last active April 11, 2017 16:58
Show Gist options
  • Save ceddlyburge/707b59a025d85f8cc0d4dea57c929e42 to your computer and use it in GitHub Desktop.
Save ceddlyburge/707b59a025d85f8cc0d4dea57c929e42 to your computer and use it in GitHub Desktop.
TidyUp class that allows you to use a `using` statement, to ensure that something is done when it goes out of scope.

TidyUp is a class that allows you to use a using statement, to ensure that something is done when it goes out of scope. It makes it obvious what the "end" type action is for a "start" type action, puts both actions next to each other and ensures that the end action gets called.

This code has a minor quality issue, in that the indentLevel++ statement could be a long way away from the indentLevel-- statement, and one could get updated without the other.

public class ObjectWriter
{
	int indentLevel;

	public void WriteRootObject(SomeClass someClass)
	{
		indentLevel = 1;
		WriteObject();
	}

	void WriteObject(SomeClass someClass)
	{
		WriteProperties(indentLevel, parent)
		indentLevel++;
		parent.Children.ForEach(child => WriteObject(child));
		// you could imagine that there are a lot more statements here
		indentLevel--;
	}
}

This can be refactored using the TidyUp class like this.

	void WriteObject(SomeClass someClass)
	{
		WriteProperties(indentLevel, parent)
		using (new TidyUp(() => indentLevel++, () => indentLevel--))
		{
			parent.Children.ForEach(child => WriteObject(child));
			// you could imagine that there are a lot more statements here
		}
	}

This makes the scope of the change to indentLevel obvious, puts both statements next to each other so that their relationship is obvious, and ensures that indentLevel-- is called. In this case it has the additional benefit that the code is indented in the same way as the output.

This can be further refactored as follows

	TidyUp Indent() => new TidyUp(() => indentLevel++, () => indentLevel--)
	
	void WriteObject(SomeClass someClass)
	{
		WriteProperties(indentLevel, parent)
		using (Indent())
		{
			parent.Children.ForEach(child => WriteObject(child));
			// you could imagine that there are a lot more statements here
		}
	}

This can obviously be used for lots of things besides indentation. We have used it frequently to do things like SavePosition, SaveColumn, SaveRow, HtmlTag, Wrap, HeaderAndFooter etc.

The TidyUp class itself is quite simple, as below.

public class TidyUp : IDisposable
{
	readonly Action tidyUp;

	public TidyUp(Action tidyUp)
	{
		Contract.Requires(tidyUp != null);
		this.tidyUp = tidyUp;
	}

	public TidyUp(Action makeMess, Action tidyUp) : this(tidyUp)
	{
		Contract.Requires(makeMess != null);

		makeMess();
	}

	public void Dispose() => tidyUp();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment