Skip to content

Instantly share code, notes, and snippets.

@IEvangelist
Last active May 31, 2019 01:38
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save IEvangelist/a93a4be129fc6311c7d810fc6315d039 to your computer and use it in GitHub Desktop.
Save IEvangelist/a93a4be129fc6311c7d810fc6315d039 to your computer and use it in GitHub Desktop.

This relies on the Newtonsoft.Json package. Once added as a package reference to your C# project, add the following class. This is an extension methods class, containing two convenience-centric extension methods:

using static Newtonsoft.Json.JsonConvert;

namespace IEvangelist.Extensions
{
    public static class ObjectExtensions
    {
        public static T FromJson<T>(this string json)
            => string.IsNullOrWhiteSpace(json)
                ? default
                : DeserializeObject<T>(json);

        public static string ToJson(this object value)
            => value is null
                ? null
                : SerializeObject(value);
    }
}

This allows the consumer to walk up to any object and invoke the .ToJson() method. This method returns a string that represents that instance of the object as its JSON equivalent. Consider the following C# object:

public class TestObject
{
    public string Name { get; set; }
    public int Number { get; set; }
    public Guid Id { get; set; } = Guid.NewGuid();
    public DateTime Date { get; set; } = DateTime.Now;
    public IEnumerable<TestObject> Children { get; set; }
}

Now, let's instantiate it like so:

var expected = new TestObject
{
    Name = "System",
    Number = 7,
    Children = new[]
    {
        new TestObject
        {
            Name = "Product",
            Number = 8,
            Children = new[]
            {
                new TestObject
                {
                    Name = "Part",
                    Number = 9
                },
                new TestObject
                {
                    Name = "Accessory",
                    Number = 10
                }
            }
        }
    }
};

Now, with this instance of our TestObject we can call the .ToJson() method - getting the JSON string representation.

var json = expected.ToJson();

We have a string named "json", with this we can then invoke the .FromJson<T>() method, providing the desired type parameter of TypeObject like so:

var actual = json.FromJson<TestObject>();

And now we have an object with the same values as originally declared and assigned from above, but in a new instance named actual. Let's put it all together now in an xUnit test.

public class ObjectExtensionsTest
{
    [Fact]
    public void SerializationTest()
    {
        var expected = new TestObject
        {
            Name = "System",
            Number = 7,
            Children = new[]
            {
                new TestObject
                {
                    Name = "Product",
                    Number = 8,
                    Children = new[]
                    {
                        new TestObject
                        {
                            Name = "Part",
                            Number = 9
                        },
                        new TestObject
                        {
                            Name = "Accessory",
                            Number = 10
                        }
                    }
                }
            }
        };

        var json = expected.ToJson();
        var actual = json.FromJson<TestObject>();

        void AreTheSame(TestObject expctd, TestObject actl)
        {
            Assert.Equal(expctd.Date, actl.Date);
            Assert.Equal(expctd.Name, actl.Name);
            Assert.Equal(expctd.Number, actl.Number);
            Assert.Equal(expctd.Id, actl.Id);
            Assert.Equal(expctd.Children?.Count() ?? 0, actl.Children?.Count() ?? 0);

            if (expctd.Children != null)
            {
                foreach (var (e, a) in 
                    expctd.Children.Join(
                        actl.Children, 
                        _ => _.Id, 
                        _ => _.Id, 
                        (l, r) => (l, r)))
                {
                    AreTheSame(e, a);
                }
            }
        }

        AreTheSame(expected, actual);
    }
}

As a bonus, if you prefer you could write these extensions as a single line - just compacting their ternary expressions a bit.

using static Newtonsoft.Json.JsonConvert;

namespace IEvangelist.Extensions
{
    public static class ObjectExtensions
    {
        public static T FromJson<T>(this string json) => string.IsNullOrWhiteSpace(json) ? default : DeserializeObject<T>(json);
        public static string ToJson(this object value) => value is null ? null : SerializeObject(value);
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment