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);
}
}