You can clone it indirectly by converting it to JSON, and converting it back to JsonNode
.
The quick & dirty way:
var copy = JsonNode.Parse(original.ToJsonString());
It should be noted that JsonNode reads and writes JSON in UTF-8 format, so this method is inefficient partly because it'll convert to UTF-16 and back (and partly because it's parsing, which we seemingly can't avoid). Here is a more efficient method:
public static JsonNode? Clone(this JsonNode? node) {
if (node == null)
return null;
// Yes, we're creating three garbage objects (array + two writers) but
// the alternative `JsonNode.Parse(original.ToJsonString())` is worse.
var buf = new ArrayBufferWriter<byte>(512);
var jwriter = new Utf8JsonWriter(buf);
node.WriteTo(jwriter);
jwriter.Flush(); // I don't know why this is necessary, but it is
return JsonNode.Parse(buf.WrittenSpan);
}
[return: NotNullIfNotNull("node")]
public static JsonObject? Clone(this JsonObject? node)
=> (JsonObject?) Clone((JsonNode) node);
[return: NotNullIfNotNull("node")]
public static JsonArray? Clone(this JsonArray? node)
=> (JsonArray?) Clone((JsonNode)node);
(this does lack an array-pooling optimization used by ToJsonString
, which relies on an internal class we don't have access to. It's still better.)
Unit test:
[Test]
public void JsonNodeCloneTest()
{
var json = JsonNode.Parse(@"{
""A"": 12345.67890,
""B"": [ ""string"", false, true, null, { ""N"": ""no"" } ]
}")!;
var jsonString1 = json.ToJsonString();
var json2 = json.Clone(); // method under test
var jsonString2 = json2.ToJsonString();
Assert.AreEqual(jsonString1, jsonString2);
}