Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Allowed write dump on generic TextWriter #118

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from
37 changes: 37 additions & 0 deletions ObjectDumper/Extensions/ObjectDumperExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.IO;

public static class ObjectDumperExtensions
{
/// <summary>
Expand Down Expand Up @@ -31,4 +33,39 @@ public static string Dump(this object element, DumpOptions dumpOptions)
{
return ObjectDumper.Dump(element, dumpOptions);
}

/// <summary>
/// Serializes the given <see cref="element" /> to string.
/// </summary>
/// <param name="element">Object to be dumped to string using the default dump options.</param>
/// <param name="writer">Where <paramref name="element"/> will dump.</param>
/// <returns></returns>
public static void Dump(this object element, TextWriter writer)
{
ObjectDumper.Dump(element, writer, default);
}

/// <summary>
/// Serializes the given <see cref="element" /> to string.
/// </summary>
/// <param name="element">Object to be dumped to string using the given <paramref name="dumpStyle" />.</param>
/// <param name="writer">Where <paramref name="element"/> will dump.</param>
/// <param name="dumpStyle">The formatting style.</param>
/// <returns></returns>
public static void Dump(this object element, TextWriter writer, DumpStyle dumpStyle)
{
ObjectDumper.Dump(element, writer, new() { DumpStyle = dumpStyle });
}

/// <summary>
/// Serializes the given <see cref="element" /> to string with additional options <see cref="dumpOptions" />.
/// </summary>
/// <param name="element">Object to be dumped to string using the given <paramref name="dumpOptions" />.</param>
/// <param name="writer">Where <paramref name="element"/> will dump.</param>
/// <param name="dumpOptions">Further options to customize the dump output.</param>
/// <returns></returns>
public static void Dump(this object element, TextWriter writer, DumpOptions dumpOptions)
{
ObjectDumper.Dump(element, writer, dumpOptions);
}
}
68 changes: 61 additions & 7 deletions ObjectDumper/Internal/DumperBase.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ObjectDumping.Internal
{
public abstract class DumperBase
{
private readonly CircularReferenceDetector circularReferenceDetector;
private readonly StringBuilder stringBuilder;
private readonly TextWriter writer;
private bool isNewLine;
private int level;

protected DumperBase(DumpOptions dumpOptions)
: this(new StringWriter(new StringBuilder()), dumpOptions)
{
}

protected DumperBase(TextWriter writer, DumpOptions dumpOptions)
{
this.DumpOptions = dumpOptions;
this.Level = 0;
this.stringBuilder = new StringBuilder();
this.circularReferenceDetector = new CircularReferenceDetector();
this.isNewLine = true;
this.writer = writer;
}

public int Level
Expand Down Expand Up @@ -68,8 +76,37 @@ protected void Write(string value)
/// <param name="indentLevel">number of indentions to prepend default 0</param>
protected void Write(string value, int indentLevel = 0)
{
this.stringBuilder.Append(this.DumpOptions.IndentChar, indentLevel * this.DumpOptions.IndentSize);
this.stringBuilder.Append(value);
for (var i = 0; i < indentLevel * this.DumpOptions.IndentSize; i++)
{
this.writer.Write(this.DumpOptions.IndentChar);
}

this.writer.Write(value);

if (value.EndsWith(this.DumpOptions.LineBreakChar))
{
this.isNewLine = true;
}
else
{
this.isNewLine = false;
}
}

protected async Task WriteAsync(string value, int indentLevel = 0, CancellationToken token = default)
{
for (var i = 0; i < indentLevel * this.DumpOptions.IndentSize; i++)
{
if (token.IsCancellationRequested)
{
return;
}

this.writer.Write(this.DumpOptions.IndentChar);
}

await this.writer.WriteAsync(value);

if (value.EndsWith(this.DumpOptions.LineBreakChar))
{
this.isNewLine = true;
Expand All @@ -88,7 +125,19 @@ protected void Write(string value, int indentLevel = 0)
/// </remarks>
protected void LineBreak()
{
this.stringBuilder.Append(this.DumpOptions.LineBreakChar);
this.writer.Write(this.DumpOptions.LineBreakChar);
this.isNewLine = true;
}

/// <summary>
/// Writes a line break to underlying <see cref="StringBuilder"/> using <see cref="DumpOptions.LineBreakChar"/>
/// </summary>
/// <remarks>
/// By definition this sets isNewLine to true
/// </remarks>
protected async Task LineBreakAsync()
{
await this.writer.WriteAsync(this.DumpOptions.LineBreakChar);
this.isNewLine = true;
}

Expand Down Expand Up @@ -175,6 +224,11 @@ protected string ResolvePropertyName(string name)
return name;
}

protected async Task FlushAsync()
{
await this.writer.FlushAsync();
}

/// <summary>
/// Converts the value of this instance to a <see cref="string"/>
/// </summary>
Expand All @@ -186,8 +240,8 @@ public override string ToString()
throw new InvalidOperationException(
"CircularReferenceDetector: Something went wrong if the circular reference detector stack is not empty at this time");
}

return this.stringBuilder.ToString();
this.writer.Flush();
return this.writer.ToString();
}
}
}
27 changes: 21 additions & 6 deletions ObjectDumper/Internal/ObjectDumperCSharp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace ObjectDumping.Internal
{
Expand All @@ -15,15 +17,28 @@ internal class ObjectDumperCSharp : DumperBase
private const string CircularReferenceDetectedComment = "// Circular reference detected";
private static readonly string[] LanguageKeywords = { "abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const", "continue", "decimal", "default", "delegate", "do", "double", "else", "enum", "event", "explicit", "extern", "false", "finally", "fixed", "float", "for", "foreach", "goto", "if", "implicit", "in", "int", "interface", "internal", "is", "lock", "long", "namespace", "new", "null", "object", "operator", "out", "override", "params", "private", "protected", "public", "readonly", "ref", "return", "sbyte", "sealed", "short", "sizeof", "stackalloc", "static", "string", "struct", "switch", "this", "throw", "true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using", "virtual", "void", "volatile", "while" };

public ObjectDumperCSharp(DumpOptions dumpOptions) : base(dumpOptions)
public ObjectDumperCSharp(TextWriter writer, DumpOptions dumpOptions)
: base(writer, dumpOptions)
{
}

public static string Dump(object element, DumpOptions dumpOptions = null)
{
var writer = new StringWriter(new StringBuilder());
Dump(element, writer, dumpOptions);
return writer.ToString();
}

public static string Dump(object element, DumpOptions dumpOptions = null)
public static void Dump(object element, TextWriter writer, DumpOptions dumpOptions = null)
{
dumpOptions ??= new DumpOptions();
if (writer == null)
{
throw new ArgumentNullException(nameof(writer), $"Parameter 'nameof(writer)' must not be null.");
}

dumpOptions ??= new DumpOptions();

var instance = new ObjectDumperCSharp(dumpOptions);
var instance = new ObjectDumperCSharp(writer, dumpOptions);
if (!dumpOptions.TrimInitialVariableName)
{
instance.Write($"var {instance.GetVariableName(element)} = ");
Expand All @@ -33,9 +48,9 @@ public static string Dump(object element, DumpOptions dumpOptions = null)
if (!dumpOptions.TrimTrailingColonName)
{
instance.Write(";");
}
}

return instance.ToString();
writer.Flush();
}

private void CreateObject(object o, int intentLevel = 0)
Expand Down
20 changes: 15 additions & 5 deletions ObjectDumper/Internal/ObjectDumperConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,41 @@
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace ObjectDumping.Internal
{
internal class ObjectDumperConsole : DumperBase
{
private const string CircularReferenceDetectedComment = "--> Circular reference detected";

public ObjectDumperConsole(DumpOptions dumpOptions) : base(dumpOptions)
public ObjectDumperConsole(TextWriter writer, DumpOptions dumpOptions) : base(writer, dumpOptions)
{
}

public static string Dump(object element, DumpOptions dumpOptions = null)
{
if (dumpOptions == null)
var writer = new StringWriter(new StringBuilder());
Dump(element, writer, dumpOptions);
return writer.ToString();
}

public static void Dump(object element, TextWriter writer, DumpOptions dumpOptions = null)
{
if (writer == null)
{
dumpOptions = new DumpOptions();
throw new ArgumentNullException(nameof(writer), $"Parameter 'nameof(writer)' must not be null.");
}

var instance = new ObjectDumperConsole(dumpOptions);
dumpOptions ??= new DumpOptions();

var instance = new ObjectDumperConsole(writer, dumpOptions);
instance.FormatValue(element);

return instance.ToString();
writer.Flush();
}

private void CreateObject(object o, int intentLevel = 0)
Expand Down
34 changes: 31 additions & 3 deletions ObjectDumper/ObjectDumper.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using System.IO;
using ObjectDumping.Internal;

// ReSharper disable once CheckNamespace
public static class ObjectDumper
{
/// <summary>
/// Serializes the given <see cref="element" /> to string.
/// Serializes the given <see cref="element" /> to string.
/// </summary>
/// <param name="element">Object to be dumped to string using the default dump options.</param>
/// <returns></returns>
Expand All @@ -15,7 +16,7 @@ public static string Dump(object element)
}

/// <summary>
/// Serializes the given <see cref="element" /> to string.
/// Serializes the given <see cref="element" /> to string.
/// </summary>
/// <param name="element">Object to be dumped to string using the given <paramref name="dumpStyle" />.</param>
/// <param name="dumpStyle">The formatting style.</param>
Expand All @@ -27,7 +28,7 @@ public static string Dump(object element, DumpStyle dumpStyle)
}

/// <summary>
/// Serializes the given <see cref="element" /> to string with additional options <see cref="dumpOptions" />.
/// Serializes the given <see cref="element" /> to string with additional options <see cref="dumpOptions" />.
/// </summary>
/// <param name="element">Object to be dumped to string using the given <paramref name="dumpOptions" />.</param>
/// <param name="dumpOptions">Further options to customize the dump output.</param>
Expand All @@ -46,4 +47,31 @@ public static string Dump(object element, DumpOptions dumpOptions)

return ObjectDumperCSharp.Dump(element, dumpOptions);
}

/// <summary>
/// Serializes the given <see cref="element" /> to string with additional options <see cref="dumpOptions" />.
/// </summary>
/// <param name="element">Object to be dumped to string using the given <paramref name="dumpOptions" />.</param>
/// <param name="writer">Where <paramref name="element"/> is write.</param>
/// <param name="dumpOptions">Further options to customize the dump output.</param>
public static void Dump(object element, TextWriter writer, DumpOptions dumpOptions)
{
if (dumpOptions == null)
{
dumpOptions = new DumpOptions();
}

switch (dumpOptions.DumpStyle)
{
case DumpStyle.Console:
ObjectDumperCSharp.Dump(element, writer, dumpOptions);
break;
case DumpStyle.CSharp:
ObjectDumperConsole.Dump(element, writer, dumpOptions);
break;
default:
break;
}
}

}
5 changes: 4 additions & 1 deletion ObjectDumper/ObjectDumper.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@
<Product>ObjectDumper.NET</Product>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<RootNamespace>ObjectDumping</RootNamespace>
<PackageReleaseNotes>4.2
<PackageReleaseNotes>4.3
- Internal refactoring: TextWriter is used to dump strings to.
- New Dump method which takes a TextWriter as parameter.
4.2
- Bug fix for circular references in collections
- Internal refactoring to handle collection dumping more efficiently
- Print element count for IEnumerables for DumpStyle.Console
Expand Down