* Enable nullable reference types.
* Update target framework to .NET 9.
* Other changes to adapt to new version of C#.
This commit is contained in:
2025-08-08 17:46:19 +02:00
parent 94b76a1001
commit 9d965e68ae
9 changed files with 1462 additions and 1468 deletions

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2016-2022 Valeriano Alfonso Rodriguez
Copyright (c) 2016-2025 Valeriano Alfonso Rodriguez
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,406 +1,409 @@
using System.Collections.Generic;
using Xunit;
namespace VAR.Json.Tests
namespace VAR.Json.Tests;
public class JsonParser_Tests
{
public class JsonParser_Tests
#region Parse
private class SwallowObject
{
#region Parse
public string? Text { get; set; }
public int Number { get; set; }
}
private class SwallowObject
{
public string Text { get; set; }
public int Number { get; set; }
}
[Fact]
public void Parse__SwallowObject()
{
JsonParser parser = new();
parser.KnownTypes.Add(typeof(SwallowObject));
SwallowObject? result = parser.Parse(@"{""Text"": ""AAAA"", ""Number"": 42}") as SwallowObject;
Assert.False(parser.Tainted);
Assert.Equal("AAAA", result?.Text);
Assert.Equal(42, result?.Number);
}
[Fact]
public void Parse__SwallowObject()
{
JsonParser parser = new JsonParser();
parser.KnownTypes.Add(typeof(SwallowObject));
SwallowObject result = parser.Parse(@"{""Text"": ""AAAA"", ""Number"": 42}") as SwallowObject;
Assert.False(parser.Tainted);
Assert.Equal("AAAA", result?.Text);
Assert.Equal(42, result.Number);
}
private class DeeperObject_L1
{
public string? Name { get; set; }
public SwallowObject? Object { get; set; }
}
private class DeeperObject_L1
{
public string Name { get; set; }
public SwallowObject Object { get; set; }
}
[Fact]
public void Parse__DeeperObject_L1()
{
JsonParser parser = new();
parser.KnownTypes.Add(typeof(SwallowObject));
parser.KnownTypes.Add(typeof(DeeperObject_L1));
DeeperObject_L1? result =
parser.Parse(@"{""Name"": ""Thing"", ""Object"": {""Text"": ""AAAA"", ""Number"": 42}}") as
DeeperObject_L1;
Assert.False(parser.Tainted);
Assert.Equal("Thing", result?.Name);
Assert.Equal("AAAA", result?.Object?.Text);
Assert.Equal(42, result?.Object?.Number);
}
[Fact]
public void Parse__DeeperObject_L1()
{
JsonParser parser = new JsonParser();
parser.KnownTypes.Add(typeof(SwallowObject));
parser.KnownTypes.Add(typeof(DeeperObject_L1));
DeeperObject_L1 result =
parser.Parse(@"{""Name"": ""Thing"", ""Object"": {""Text"": ""AAAA"", ""Number"": 42}}") as
DeeperObject_L1;
Assert.False(parser.Tainted);
Assert.Equal("Thing", result.Name);
Assert.Equal("AAAA", result.Object.Text);
Assert.Equal(42, result.Object.Number);
}
private class DeeperObject_L2
{
public int Count { get; set; }
public DeeperObject_L1? Object { get; set; }
}
private class DeeperObject_L2
{
public int Count { get; set; }
public DeeperObject_L1 Object { get; set; }
}
[Fact]
public void Parse__DeeperObject_L2()
{
JsonParser parser = new();
parser.KnownTypes.Add(typeof(SwallowObject));
parser.KnownTypes.Add(typeof(DeeperObject_L1));
parser.KnownTypes.Add(typeof(DeeperObject_L2));
DeeperObject_L2? result =
parser.Parse(
@"{""Count"": 1, ""Object"": {""Name"": ""Thing"", ""Object"": {""Text"": ""AAAA"", ""Number"": 42}}}")
as DeeperObject_L2;
Assert.False(parser.Tainted);
Assert.NotNull(result);
Assert.Equal(1, result?.Count);
Assert.Equal("Thing", result?.Object?.Name);
Assert.Equal("AAAA", result?.Object?.Object?.Text);
Assert.Equal(42, result?.Object?.Object?.Number);
}
[Fact]
public void Parse__DeeperObject_L2()
{
JsonParser parser = new JsonParser();
parser.KnownTypes.Add(typeof(SwallowObject));
parser.KnownTypes.Add(typeof(DeeperObject_L1));
parser.KnownTypes.Add(typeof(DeeperObject_L2));
DeeperObject_L2 result =
parser.Parse(
@"{""Count"": 1, ""Object"": {""Name"": ""Thing"", ""Object"": {""Text"": ""AAAA"", ""Number"": 42}}}")
as DeeperObject_L2;
Assert.False(parser.Tainted);
Assert.Equal(1, result.Count);
Assert.Equal("Thing", result.Object.Name);
Assert.Equal("AAAA", result.Object.Object.Text);
Assert.Equal(42, result.Object.Object.Number);
}
[Fact]
public void Parse__SwallowObjectArray()
{
JsonParser parser = new();
parser.KnownTypes.Add(typeof(SwallowObject));
List<SwallowObject>? result = parser.Parse(@"[{""Text"": ""AAAA"", ""Number"": 42}]") as List<SwallowObject>;
Assert.False(parser.Tainted);
Assert.NotNull(result);
Assert.Single(result);
Assert.Equal("AAAA", result?[0].Text);
Assert.Equal(42, result?[0].Number);
}
[Fact]
public void Parse__SwallowObjectArray()
{
JsonParser parser = new JsonParser();
parser.KnownTypes.Add(typeof(SwallowObject));
List<SwallowObject> result = parser.Parse(@"[{""Text"": ""AAAA"", ""Number"": 42}]") as List<SwallowObject>;
Assert.False(parser.Tainted);
Assert.Single(result);
Assert.Equal("AAAA", result[0].Text);
Assert.Equal(42, result[0].Number);
}
private class DeeperObjectArray_L1
{
public int Count { get; set; }
public List<SwallowObject>? Array { get; set; }
}
private class DeeperObjectArray_L1
{
public int Count { get; set; }
public List<SwallowObject> Array { get; set; }
}
[Fact]
public void Parse__DeeperObjectArray_L1()
{
JsonParser parser = new();
parser.KnownTypes.Add(typeof(SwallowObject));
parser.KnownTypes.Add(typeof(DeeperObjectArray_L1));
DeeperObjectArray_L1? result =
parser.Parse(@"{""Count"": 1, ""Array"": [{""Text"": ""AAAA"", ""Number"": 42}]}") as
DeeperObjectArray_L1;
Assert.False(parser.Tainted);
Assert.NotNull(result);
Assert.Equal(1, result?.Count);
Assert.Equal("AAAA", result?.Array?[0].Text);
Assert.Equal(42, result?.Array?[0].Number);
}
[Fact]
public void Parse__DeeperObjectArray_L1()
{
JsonParser parser = new JsonParser();
parser.KnownTypes.Add(typeof(SwallowObject));
parser.KnownTypes.Add(typeof(DeeperObjectArray_L1));
DeeperObjectArray_L1 result =
parser.Parse(@"{""Count"": 1, ""Array"": [{""Text"": ""AAAA"", ""Number"": 42}]}") as
DeeperObjectArray_L1;
Assert.False(parser.Tainted);
Assert.Equal(1, result.Count);
Assert.Equal("AAAA", result.Array[0].Text);
Assert.Equal(42, result.Array[0].Number);
}
private class DeeperObjectArray_L2
{
public string Name { get; set; } = string.Empty;
public List<DeeperObjectArray_L1> Objects { get; set; } = [];
}
private class DeeperObjectArray_L2
{
public string Name { get; set; }
public List<DeeperObjectArray_L1> Objects { get; set; }
}
[Fact]
public void Parse__DeeperObjectArray_L2()
{
JsonParser parser = new();
parser.KnownTypes.Add(typeof(SwallowObject));
parser.KnownTypes.Add(typeof(DeeperObjectArray_L1));
parser.KnownTypes.Add(typeof(DeeperObjectArray_L2));
DeeperObjectArray_L2? result =
parser.Parse(
@"{""Name"": ""Thing"", ""Objects"": [{""Count"": 1, ""Array"": [{""Text"": ""AAAA"", ""Number"": 42}]}]}")
as DeeperObjectArray_L2;
Assert.False(parser.Tainted);
Assert.Equal("Thing", result?.Name);
Assert.Equal(1, result?.Objects[0].Count);
Assert.Equal("AAAA", result?.Objects[0].Array?[0].Text);
Assert.Equal(42, result?.Objects[0].Array?[0].Number);
}
[Fact]
public void Parse__DeeperObjectArray_L2()
{
JsonParser parser = new JsonParser();
parser.KnownTypes.Add(typeof(SwallowObject));
parser.KnownTypes.Add(typeof(DeeperObjectArray_L1));
parser.KnownTypes.Add(typeof(DeeperObjectArray_L2));
DeeperObjectArray_L2 result =
parser.Parse(
@"{""Name"": ""Thing"", ""Objects"": [{""Count"": 1, ""Array"": [{""Text"": ""AAAA"", ""Number"": 42}]}]}")
as DeeperObjectArray_L2;
Assert.False(parser.Tainted);
Assert.Equal("Thing", result.Name);
Assert.Equal(1, result.Objects[0].Count);
Assert.Equal("AAAA", result.Objects[0].Array[0].Text);
Assert.Equal(42, result.Objects[0].Array[0].Number);
}
#endregion Parse
#endregion Parse
#region Validity tests
#region Validity tests
[Fact]
public void Parse__Validity_Fail01()
{
JsonParser parser = new();
parser.Parse(@"""A JSON payload should be an object or array, not a string.""");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail01()
{
JsonParser parser = new JsonParser();
parser.Parse(@"""A JSON payload should be an object or array, not a string.""");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail02()
{
JsonParser parser = new();
parser.Parse(@"[""Unclosed array""");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail02()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[""Unclosed array""");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail03()
{
JsonParser parser = new();
parser.Parse(@"{unquoted_key: ""keys must be quoted""}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail03()
{
JsonParser parser = new JsonParser();
parser.Parse(@"{unquoted_key: ""keys must be quoted""}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail04()
{
JsonParser parser = new();
parser.Parse(@"[""extra comma"",]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail04()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[""extra comma"",]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail05()
{
JsonParser parser = new();
parser.Parse(@"[""double extra comma"",,]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail05()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[""double extra comma"",,]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail06()
{
JsonParser parser = new();
parser.Parse(@"[ , ""<-- missing value""]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail06()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[ , ""<-- missing value""]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail07()
{
JsonParser parser = new();
parser.Parse(@"[""Comma after the close""],");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail07()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[""Comma after the close""],");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail08()
{
JsonParser parser = new();
parser.Parse(@"[""Extra close""]]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail08()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[""Extra close""]]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail09()
{
JsonParser parser = new();
parser.Parse(@"{""Extra comma"": true,}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail09()
{
JsonParser parser = new JsonParser();
parser.Parse(@"{""Extra comma"": true,}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail10()
{
JsonParser parser = new();
parser.Parse(@"{""Extra value after close"": true} ""misplaced quoted value""");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail10()
{
JsonParser parser = new JsonParser();
parser.Parse(@"{""Extra value after close"": true} ""misplaced quoted value""");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail11()
{
JsonParser parser = new();
parser.Parse(@"{""Illegal expression"": 1 + 2}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail11()
{
JsonParser parser = new JsonParser();
parser.Parse(@"{""Illegal expression"": 1 + 2}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail12()
{
JsonParser parser = new();
parser.Parse(@"{""Illegal invocation"": alert()}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail12()
{
JsonParser parser = new JsonParser();
parser.Parse(@"{""Illegal invocation"": alert()}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail13()
{
JsonParser parser = new();
parser.Parse(@"{""Numbers cannot have leading zeroes"": 013}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail13()
{
JsonParser parser = new JsonParser();
parser.Parse(@"{""Numbers cannot have leading zeroes"": 013}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail14()
{
JsonParser parser = new();
parser.Parse(@"{""Numbers cannot be hex"": 0x14}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail14()
{
JsonParser parser = new JsonParser();
parser.Parse(@"{""Numbers cannot be hex"": 0x14}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail15()
{
JsonParser parser = new();
parser.Parse(@"[""Illegal backslash escape: \x15""]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail15()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[""Illegal backslash escape: \x15""]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail16()
{
JsonParser parser = new();
parser.Parse(@"[\naked]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail16()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[\naked]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail17()
{
JsonParser parser = new();
parser.Parse(@"[""Illegal backslash escape: \017""]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail17()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[""Illegal backslash escape: \017""]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail18()
{
JsonParser parser = new();
parser.Parse(@"[[[[[[[[[[[[[[[[[[[[""Too deep""]]]]]]]]]]]]]]]]]]]]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail18()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[[[[[[[[[[[[[[[[[[[[""Too deep""]]]]]]]]]]]]]]]]]]]]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail19()
{
JsonParser parser = new();
parser.Parse(@"{""Missing colon"" null}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail19()
{
JsonParser parser = new JsonParser();
parser.Parse(@"{""Missing colon"" null}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail20()
{
JsonParser parser = new();
parser.Parse(@"{""Double colon"":: null}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail20()
{
JsonParser parser = new JsonParser();
parser.Parse(@"{""Double colon"":: null}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail21()
{
JsonParser parser = new();
parser.Parse(@"{""Comma instead of colon"", null}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail21()
{
JsonParser parser = new JsonParser();
parser.Parse(@"{""Comma instead of colon"", null}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail22()
{
JsonParser parser = new();
parser.Parse(@"[""Colon instead of comma"": false]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail22()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[""Colon instead of comma"": false]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail23()
{
JsonParser parser = new();
parser.Parse(@"[""Bad value"", truth]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail23()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[""Bad value"", truth]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail24()
{
JsonParser parser = new();
parser.Parse(@"['single quote']");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail24()
{
JsonParser parser = new JsonParser();
parser.Parse(@"['single quote']");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail25()
{
JsonParser parser = new();
parser.Parse(@"["" tab character in string ""]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail25()
{
JsonParser parser = new JsonParser();
parser.Parse(@"["" tab character in string ""]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail26()
{
JsonParser parser = new();
parser.Parse(@"[""tab\ character\ in\ string\ ""]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail26()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[""tab\ character\ in\ string\ ""]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail27()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[""line
[Fact]
public void Parse__Validity_Fail27()
{
JsonParser parser = new();
parser.Parse(@"[""line
break""]");
Assert.True(parser.Tainted);
}
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail28()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[""line\
[Fact]
public void Parse__Validity_Fail28()
{
JsonParser parser = new();
parser.Parse(@"[""line\
break""]");
Assert.True(parser.Tainted);
}
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail29()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[0e]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail29()
{
JsonParser parser = new();
parser.Parse(@"[0e]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail30()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[0e+]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail30()
{
JsonParser parser = new();
parser.Parse(@"[0e+]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail31()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[0e+-1]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail31()
{
JsonParser parser = new();
parser.Parse(@"[0e+-1]");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail32()
{
JsonParser parser = new JsonParser();
parser.Parse(@"{""Comma instead if closing brace"": true,");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail32()
{
JsonParser parser = new();
parser.Parse(@"{""Comma instead if closing brace"": true,");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail33()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[""mismatch""}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Fail33()
{
JsonParser parser = new();
parser.Parse(@"[""mismatch""}");
Assert.True(parser.Tainted);
}
[Fact]
public void Parse__Validity_Pass01()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[
[Fact]
public void Parse__Validity_Pass01()
{
JsonParser parser = new();
parser.Parse(@"[
""JSON Test Pattern pass1"",
{""object with 1 member"":[""array with 1 element""]},
{},
@@ -458,31 +461,30 @@ break""]");
1e-1,
1e00,2e+00,2e-00
,""rosebud""]");
Assert.False(parser.Tainted);
}
Assert.False(parser.Tainted);
}
[Fact]
public void Parse__Validity_Pass02()
{
JsonParser parser = new JsonParser();
parser.Parse(@"[[[[[[[[[[[[[[[[[[[""Not too deep""]]]]]]]]]]]]]]]]]]]");
Assert.False(parser.Tainted);
}
[Fact]
public void Parse__Validity_Pass02()
{
JsonParser parser = new();
parser.Parse(@"[[[[[[[[[[[[[[[[[[[""Not too deep""]]]]]]]]]]]]]]]]]]]");
Assert.False(parser.Tainted);
}
[Fact]
public void Parse__Validity_Pass03()
{
JsonParser parser = new JsonParser();
parser.Parse(@"{
[Fact]
public void Parse__Validity_Pass03()
{
JsonParser parser = new();
parser.Parse(@"{
""JSON Test Pattern pass3"": {
""The outermost value"": ""must be an object or array."",
""In this test"": ""It is an object.""
}
}
");
Assert.False(parser.Tainted);
}
#endregion Validity tests
Assert.False(parser.Tainted);
}
#endregion Validity tests
}

View File

@@ -1,9 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
<LangVersion>default</LangVersion>
</PropertyGroup>
<ItemGroup>

View File

@@ -52,4 +52,25 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PublicFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=15b5b1f1_002D457c_002D4ca6_002Db278_002D5615aedc07d3/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="_" Suffix="" Style="aaBb_AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=236f7aa5_002D7b06_002D43ca_002Dbf2a_002D9b31bfcff09a/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Private" Description="Constant fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="CONSTANT_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=4a98fdf6_002D7d98_002D4f5a_002Dafeb_002Dea44ad98c70c/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="_" Suffix="" Style="aaBb_AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=53eecf85_002Dd821_002D40e8_002Dac97_002Dfdb734542b84/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Instance fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=61a991a4_002Dd0a3_002D4d19_002D90a5_002Df8f4d75c30c1/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Local variables"&gt;&lt;ElementKinds&gt;&lt;Kind Name="LOCAL_VARIABLE" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aaBb_AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=669e5282_002Dfb4b_002D4e90_002D91e7_002D07d269d04b60/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Constant fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="CONSTANT_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=70345118_002D4b40_002D4ece_002D937c_002Dbbeb7a0b2e70/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Static fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=8284009d_002De743_002D4d89_002D9402_002Da5bf9a89b657/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Methods"&gt;&lt;ElementKinds&gt;&lt;Kind Name="METHOD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=8a85b61a_002D1024_002D4f87_002Db9ef_002D1fdae19930a1/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Parameters"&gt;&lt;ElementKinds&gt;&lt;Kind Name="PARAMETER" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aaBb_AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=8b8504e3_002Df0be_002D4c14_002D9103_002Dc732f2bddc15/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Enum members"&gt;&lt;ElementKinds&gt;&lt;Kind Name="ENUM_MEMBER" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb_AaBb"&gt;&lt;ExtraRule Prefix="T" Suffix="" Style="AaBb_AaBb" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a0b4bc4d_002Dd13b_002D4a37_002Db37e_002Dc9c6864e4302/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"&gt;&lt;ElementKinds&gt;&lt;Kind Name="NAMESPACE" /&gt;&lt;Kind Name="CLASS" /&gt;&lt;Kind Name="STRUCT" /&gt;&lt;Kind Name="ENUM" /&gt;&lt;Kind Name="DELEGATE" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a4f433b8_002Dabcd_002D4e55_002Da08f_002D82e78cef0f0c/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Local constants"&gt;&lt;ElementKinds&gt;&lt;Kind Name="LOCAL_CONSTANT" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a7a3339e_002D4e89_002D4319_002D9735_002Da9dc4cb74cc7/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Interfaces"&gt;&lt;ElementKinds&gt;&lt;Kind Name="INTERFACE" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="I" Suffix="" Style="AaBb_AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=c85a0503_002D4de2_002D40f1_002D9cd6_002Da4054c05d384/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Properties"&gt;&lt;ElementKinds&gt;&lt;Kind Name="PROPERTY" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=c873eafb_002Dd57f_002D481d_002D8c93_002D77f6863c2f88/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Static readonly fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=f9fce829_002De6f4_002D4cb2_002D80f1_002D5497c44f51df/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="_" Suffix="" Style="aaBb_AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>

File diff suppressed because it is too large Load Diff

View File

@@ -5,477 +5,468 @@ using System.IO;
using System.Linq;
using System.Reflection;
namespace VAR.Json
namespace VAR.Json;
public class JsonWriterConfiguration
{
public class JsonWriterConfiguration
private readonly bool _indent;
public bool Indent => _indent;
private readonly bool _useTabForIndent;
public bool UseTabForIndent => _useTabForIndent;
private readonly int _indentChars;
public int IndentChars => _indentChars;
private readonly int _indentThreshold;
public int IndentThreshold => _indentThreshold;
public JsonWriterConfiguration(
bool indent = false,
bool useTabForIndent = false,
int indentChars = 4,
int indentThreshold = 3)
{
private readonly bool _indent;
_indent = indent;
_useTabForIndent = useTabForIndent;
_indentChars = indentChars;
_indentThreshold = indentThreshold;
}
public bool Indent => _indent;
public bool Equals(JsonWriterConfiguration other) =>
other.Indent == Indent &&
other.UseTabForIndent == UseTabForIndent &&
other.IndentChars == IndentChars &&
other.IndentThreshold == IndentThreshold &&
true;
private readonly bool _useTabForIndent;
public bool UseTabForIndent => _useTabForIndent;
private readonly int _indentChars;
public int IndentChars => _indentChars;
private readonly int _indentThreshold;
public int IndentThreshold => _indentThreshold;
public JsonWriterConfiguration(
bool indent = false,
bool useTabForIndent = false,
int indentChars = 4,
int indentThreshold = 3)
public override bool Equals(object? other)
{
if (other is JsonWriterConfiguration configuration)
{
_indent = indent;
_useTabForIndent = useTabForIndent;
_indentChars = indentChars;
_indentThreshold = indentThreshold;
return Equals(configuration);
}
public bool Equals(JsonWriterConfiguration other)
return false;
}
public override int GetHashCode()
{
return _indent.GetHashCode() ^ _useTabForIndent.GetHashCode() ^ _indentChars.GetHashCode() ^ _indentThreshold.GetHashCode();
}
}
public class JsonWriter
{
#region Declarations
private readonly JsonWriterConfiguration _config;
#endregion Declarations
#region Creator
public JsonWriter(JsonWriterConfiguration? config = null)
{
_config = config ?? new JsonWriterConfiguration();
}
#endregion Creator
#region Private methods
private bool IsValue(object? obj)
{
if (obj == null)
{
return
other.Indent == Indent &&
other.UseTabForIndent == UseTabForIndent &&
other.IndentChars == IndentChars &&
other.IndentThreshold == IndentThreshold &&
true;
return true;
}
public override bool Equals(object other)
if (
(obj is float) ||
(obj is double) ||
(obj is short) ||
(obj is int) ||
(obj is long) ||
(obj is string) ||
(obj is bool) ||
false)
{
if (other is JsonWriterConfiguration configuration)
{
return Equals(configuration);
}
return false;
return true;
}
public override int GetHashCode()
return false;
}
private void WriteIndent(TextWriter textWriter, int level)
{
if (!_config.Indent)
{
return _indent.GetHashCode() ^ _useTabForIndent.GetHashCode() ^ _indentChars.GetHashCode() ^
_indentThreshold.GetHashCode();
return;
}
textWriter.Write('\n');
if (_config.UseTabForIndent)
{
for (int i = 0; i < level; i++) { textWriter.Write('\t'); }
}
else
{
int n = level * _config.IndentChars;
for (int i = 0; i < n; i++) { textWriter.Write(' '); }
}
}
public class JsonWriter
private void WriteString(TextWriter textWriter, string str)
{
#region Declarations
private readonly JsonWriterConfiguration _config;
#endregion Declarations
#region Creator
public JsonWriter(JsonWriterConfiguration config = null)
textWriter.Write('"');
int n = str.Length;
for (int i = 0; i < n; i++)
{
_config = config ?? new JsonWriterConfiguration();
char c = str[i];
if (c == '"') { textWriter.Write("\\\""); }
else if (c == '\\') { textWriter.Write("\\\\"); }
else if (c == '/') { textWriter.Write("\\/"); }
else if (c == '\b') { textWriter.Write("\\b"); }
else if (c == '\f') { textWriter.Write("\\f"); }
else if (c == '\n') { textWriter.Write("\\n"); }
else if (c == '\r') { textWriter.Write("\\r"); }
else if (c == '\t') { textWriter.Write("\\t"); }
else if (c < 32 || c >= 127) { textWriter.Write("\\u{0:X04}", (int)c); }
else { textWriter.Write(c); }
}
#endregion Creator
textWriter.Write('"');
}
#region Private methods
private bool IsValue(object obj)
private void WriteValue(TextWriter textWriter, object? obj, List<object?> parentLevels)
{
if (obj == null || obj is DBNull)
{
if (obj == null)
{
return true;
}
if (
(obj is float) ||
(obj is double) ||
(obj is short) ||
(obj is int) ||
(obj is long) ||
(obj is string) ||
(obj is bool) ||
false)
{
return true;
}
return false;
// NULL
textWriter.Write("null");
}
private void WriteIndent(TextWriter textWriter, int level)
else if (
(obj is float) ||
(obj is double) ||
(obj is short) ||
(obj is int) ||
(obj is long) ||
false)
{
if (!_config.Indent)
{
return;
}
textWriter.Write('\n');
if (_config.UseTabForIndent)
{
for (int i = 0; i < level; i++) { textWriter.Write('\t'); }
}
else
{
int n = level * _config.IndentChars;
for (int i = 0; i < n; i++) { textWriter.Write(' '); }
}
// Numbers
textWriter.Write(obj.ToString());
}
private void WriteString(TextWriter textWriter, string str)
{
textWriter.Write('"');
int n = str.Length;
for (int i = 0; i < n; i++)
else
switch (obj)
{
char c = str[i];
if (c == '"') { textWriter.Write("\\\""); }
else if (c == '\\') { textWriter.Write("\\\\"); }
else if (c == '/') { textWriter.Write("\\/"); }
else if (c == '\b') { textWriter.Write("\\b"); }
else if (c == '\f') { textWriter.Write("\\f"); }
else if (c == '\n') { textWriter.Write("\\n"); }
else if (c == '\r') { textWriter.Write("\\r"); }
else if (c == '\t') { textWriter.Write("\\t"); }
else if (c < 32 || c >= 127) { textWriter.Write("\\u{0:X04}", (int)c); }
else { textWriter.Write(c); }
}
textWriter.Write('"');
}
private void WriteValue(TextWriter textWriter, object obj, List<object> parentLevels)
{
if (obj == null || obj is DBNull)
{
// NULL
textWriter.Write("null");
}
else if (
(obj is float) ||
(obj is double) ||
(obj is short) ||
(obj is int) ||
(obj is long) ||
false)
{
// Numbers
textWriter.Write(obj.ToString());
}
else
switch (obj)
{
case string valString:
// Strings
WriteString(textWriter, valString);
break;
case bool valBool:
// Booleans
textWriter.Write(valBool ? "true" : "false");
break;
case DateTime valDateTime:
// DateTime
textWriter.Write('"');
textWriter.Write(valDateTime.ToString("yyyy-MM-ddTHH:mm:ss"));
textWriter.Write('"');
break;
case IDictionary _:
// Objects
WriteObject(textWriter, obj, parentLevels);
break;
case IEnumerable _:
// Array/List
WriteList(textWriter, obj, parentLevels);
break;
default:
// Reflected object
WriteReflectedObject(textWriter, obj, parentLevels);
break;
}
}
private void WriteList(TextWriter textWriter, object obj, List<object> parentLevels)
{
IEnumerable list = ((IEnumerable)obj).Cast<object>().ToList();
int n = 0;
// Check if it is a leaf object
bool isLeaf = true;
foreach (object childObj in list)
{
if (!IsValue(childObj))
{
isLeaf = false;
}
n++;
}
// Empty
if (n == 0)
{
textWriter.Write("[ ]");
return;
}
// Write array
bool first = true;
textWriter.Write("[ ");
if (!isLeaf || n > _config.IndentThreshold)
{
WriteIndent(textWriter, parentLevels.Count + 1);
}
foreach (object childObj in list)
{
if (!first)
{
textWriter.Write(", ");
if (!isLeaf || n > _config.IndentThreshold)
{
WriteIndent(textWriter, parentLevels.Count + 1);
}
}
first = false;
parentLevels.Add(obj);
WriteValue(textWriter, childObj, parentLevels);
parentLevels.Remove(obj);
}
if (!isLeaf || n > _config.IndentThreshold)
{
WriteIndent(textWriter, parentLevels.Count);
}
textWriter.Write(" ]");
}
private void WriteObject(TextWriter textWriter, object obj, List<object> parentLevels)
{
IDictionary map = (IDictionary)obj;
int n = map.Count;
// Empty
if (map.Count == 0)
{
textWriter.Write("{ }");
return;
}
// Check if it is a leaf object
bool isLeaf = true;
foreach (object value in map.Values)
{
if (!IsValue(value))
{
isLeaf = false;
case string valString:
// Strings
WriteString(textWriter, valString);
break;
}
case bool valBool:
// Booleans
textWriter.Write(valBool ? "true" : "false");
break;
case DateTime valDateTime:
// DateTime
textWriter.Write('"');
textWriter.Write(valDateTime.ToString("yyyy-MM-ddTHH:mm:ss"));
textWriter.Write('"');
break;
case IDictionary _:
// Objects
WriteObject(textWriter, obj, parentLevels);
break;
case IEnumerable _:
// Array/List
WriteList(textWriter, obj, parentLevels);
break;
default:
// Reflected object
WriteReflectedObject(textWriter, obj, parentLevels);
break;
}
}
private void WriteList(TextWriter textWriter, object obj, List<object?> parentLevels)
{
IEnumerable list = ((IEnumerable)obj).Cast<object>().ToList();
int n = 0;
// Check if it is a leaf object
bool isLeaf = true;
foreach (object childObj in list)
{
if (!IsValue(childObj))
{
isLeaf = false;
}
// Write object
bool first = true;
textWriter.Write("{ ");
if (!isLeaf || n > _config.IndentThreshold)
{
WriteIndent(textWriter, parentLevels.Count + 1);
}
n++;
}
foreach (object key in map.Keys)
// Empty
if (n == 0)
{
textWriter.Write("[ ]");
return;
}
// Write array
bool first = true;
textWriter.Write("[ ");
if (!isLeaf || n > _config.IndentThreshold)
{
WriteIndent(textWriter, parentLevels.Count + 1);
}
foreach (object childObj in list)
{
if (!first)
{
object value = map[key];
if (!first)
textWriter.Write(", ");
if (!isLeaf || n > _config.IndentThreshold)
{
textWriter.Write(", ");
if (!isLeaf || n > _config.IndentThreshold)
{
WriteIndent(textWriter, parentLevels.Count + 1);
}
WriteIndent(textWriter, parentLevels.Count + 1);
}
}
first = false;
WriteString(textWriter, Convert.ToString(key));
textWriter.Write(": ");
parentLevels.Add(obj);
first = false;
parentLevels.Add(obj);
WriteValue(textWriter, childObj, parentLevels);
parentLevels.Remove(obj);
}
if (!isLeaf || n > _config.IndentThreshold)
{
WriteIndent(textWriter, parentLevels.Count);
}
textWriter.Write(" ]");
}
private void WriteObject(TextWriter textWriter, object obj, List<object?> parentLevels)
{
IDictionary map = (IDictionary)obj;
int n = map.Count;
// Empty
if (map.Count == 0)
{
textWriter.Write("{ }");
return;
}
// Check if it is a leaf object
bool isLeaf = true;
foreach (object value in map.Values)
{
if (!IsValue(value))
{
isLeaf = false;
break;
}
}
// Write object
bool first = true;
textWriter.Write("{ ");
if (!isLeaf || n > _config.IndentThreshold)
{
WriteIndent(textWriter, parentLevels.Count + 1);
}
foreach (object key in map.Keys)
{
object? value = map[key];
if (!first)
{
textWriter.Write(", ");
if (!isLeaf || n > _config.IndentThreshold)
{
WriteIndent(textWriter, parentLevels.Count + 1);
}
}
first = false;
WriteString(textWriter, Convert.ToString(key) ?? string.Empty);
textWriter.Write(": ");
parentLevels.Add(obj);
WriteValue(textWriter, value, parentLevels);
parentLevels.Remove(obj);
}
if (!isLeaf || n > _config.IndentThreshold)
{
WriteIndent(textWriter, parentLevels.Count);
}
textWriter.Write(" }");
}
private void WriteReflectedObject(TextWriter textWriter, object obj, List<object?> parentLevels)
{
Type type = obj.GetType();
PropertyInfo[] rawProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
List<PropertyInfo> properties = [];
foreach (PropertyInfo property in rawProperties)
{
if (property.CanRead == false) { continue; }
properties.Add(property);
}
int n = properties.Count;
// Empty
if (n == 0)
{
textWriter.Write("{ }");
return;
}
// Check if it is a leaf object
bool isLeaf = true;
foreach (PropertyInfo property in properties)
{
object? value = property.GetValue(obj, null);
if (!IsValue(value))
{
isLeaf = false;
break;
}
}
// Write object
bool first = true;
textWriter.Write("{ ");
if (!isLeaf || n > _config.IndentThreshold)
{
WriteIndent(textWriter, parentLevels.Count + 1);
}
foreach (PropertyInfo property in properties)
{
object? value = null;
MethodInfo? getMethod = property.GetGetMethod();
ParameterInfo[] parameters = getMethod?.GetParameters() ?? [];
if (parameters.Length == 0)
{
value = property.GetValue(obj, null);
}
if (!first)
{
textWriter.Write(", ");
if (!isLeaf || n > _config.IndentThreshold)
{
WriteIndent(textWriter, parentLevels.Count + 1);
}
}
first = false;
WriteString(textWriter, property.Name);
textWriter.Write(": ");
parentLevels.Add(obj);
if (value != obj && parentLevels.Contains(value) == false)
{
WriteValue(textWriter, value, parentLevels);
parentLevels.Remove(obj);
}
if (!isLeaf || n > _config.IndentThreshold)
else
{
WriteIndent(textWriter, parentLevels.Count);
WriteValue(textWriter, null, parentLevels);
}
textWriter.Write(" }");
parentLevels.Remove(obj);
}
private void WriteReflectedObject(TextWriter textWriter, object obj, List<object> parentLevels)
if (!isLeaf || n > _config.IndentThreshold)
{
Type type = obj.GetType();
PropertyInfo[] rawProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
List<PropertyInfo> properties = new List<PropertyInfo>();
foreach (PropertyInfo property in rawProperties)
{
if (property.CanRead == false) { continue; }
properties.Add(property);
}
int n = properties.Count;
// Empty
if (n == 0)
{
textWriter.Write("{ }");
return;
}
// Check if it is a leaf object
bool isLeaf = true;
foreach (PropertyInfo property in properties)
{
object value = property.GetValue(obj, null);
if (!IsValue(value))
{
isLeaf = false;
break;
}
}
// Write object
bool first = true;
textWriter.Write("{ ");
if (!isLeaf || n > _config.IndentThreshold)
{
WriteIndent(textWriter, parentLevels.Count + 1);
}
foreach (PropertyInfo property in properties)
{
object value = null;
MethodInfo getMethod = property.GetGetMethod();
ParameterInfo[] parameters = getMethod.GetParameters();
if (parameters.Length == 0)
{
value = property.GetValue(obj, null);
}
if (!first)
{
textWriter.Write(", ");
if (!isLeaf || n > _config.IndentThreshold)
{
WriteIndent(textWriter, parentLevels.Count + 1);
}
}
first = false;
WriteString(textWriter, property.Name);
textWriter.Write(": ");
parentLevels.Add(obj);
if (value != obj && parentLevels.Contains(value) == false)
{
WriteValue(textWriter, value, parentLevels);
}
else
{
WriteValue(textWriter, null, parentLevels);
}
parentLevels.Remove(obj);
}
if (!isLeaf || n > _config.IndentThreshold)
{
WriteIndent(textWriter, parentLevels.Count);
}
textWriter.Write(" }");
WriteIndent(textWriter, parentLevels.Count);
}
#endregion Private methods
textWriter.Write(" }");
}
#region Public methods
#endregion Private methods
public TextWriter Write(object obj, TextWriter textWriter)
#region Public methods
public TextWriter Write(object obj, TextWriter? textWriter)
{
textWriter ??= new StringWriter();
WriteValue(textWriter, obj, []);
return textWriter;
}
public string Write(object obj)
{
StringWriter textWriter = new();
WriteValue(textWriter, obj, []);
return textWriter.ToString();
}
private static readonly Dictionary<JsonWriterConfiguration, JsonWriter> _dictInstances = new();
public static string WriteObject(object obj,
JsonWriterConfiguration? config = null,
bool indent = false,
bool useTabForIndent = false,
int indentChars = 4,
int indentThreshold = 3)
{
JsonWriter? jsonWriter = null;
if (config != null)
{
if (textWriter == null)
if (_dictInstances.ContainsKey(config) == false)
{
textWriter = new StringWriter();
jsonWriter = new JsonWriter(config);
_dictInstances.Add(config, jsonWriter);
}
WriteValue(textWriter, obj, new List<object>());
return textWriter;
}
public string Write(object obj)
{
StringWriter textWriter = new StringWriter();
WriteValue(textWriter, obj, new List<object>());
return textWriter.ToString();
}
private static readonly Dictionary<JsonWriterConfiguration, JsonWriter> _dictInstances =
new Dictionary<JsonWriterConfiguration, JsonWriter>();
public static string WriteObject(object obj,
JsonWriterConfiguration config = null,
bool indent = false,
bool useTabForIndent = false,
int indentChars = 4,
int indentThreshold = 3)
{
JsonWriter jsonWriter = null;
if (config != null)
else
{
if (_dictInstances.ContainsKey(config) == false)
{
jsonWriter = new JsonWriter(config);
_dictInstances.Add(config, jsonWriter);
}
else
{
jsonWriter = _dictInstances[config];
}
return jsonWriter.Write(obj);
jsonWriter = _dictInstances[config];
}
foreach (KeyValuePair<JsonWriterConfiguration, JsonWriter> pair in _dictInstances)
{
if (
pair.Key.Indent == indent &&
pair.Key.UseTabForIndent == useTabForIndent &&
pair.Key.IndentChars == indentChars &&
pair.Key.IndentThreshold == indentThreshold &&
true)
{
jsonWriter = pair.Value;
break;
}
}
if (jsonWriter != null)
{
return jsonWriter.Write(obj);
}
JsonWriterConfiguration jsonWriterConfiguration = new JsonWriterConfiguration(
indent: indent,
useTabForIndent: useTabForIndent,
indentChars: indentChars,
indentThreshold: indentThreshold);
jsonWriter = new JsonWriter(jsonWriterConfiguration);
_dictInstances.Add(jsonWriterConfiguration, jsonWriter);
return jsonWriter.Write(obj);
}
#endregion Public methods
foreach (KeyValuePair<JsonWriterConfiguration, JsonWriter> pair in _dictInstances)
{
if (
pair.Key.Indent == indent &&
pair.Key.UseTabForIndent == useTabForIndent &&
pair.Key.IndentChars == indentChars &&
pair.Key.IndentThreshold == indentThreshold &&
true)
{
jsonWriter = pair.Value;
break;
}
}
if (jsonWriter != null)
{
return jsonWriter.Write(obj);
}
JsonWriterConfiguration jsonWriterConfiguration = new(
indent: indent,
useTabForIndent: useTabForIndent,
indentChars: indentChars,
indentThreshold: indentThreshold);
jsonWriter = new JsonWriter(jsonWriterConfiguration);
_dictInstances.Add(jsonWriterConfiguration, jsonWriter);
return jsonWriter.Write(obj);
}
#endregion Public methods
}

View File

@@ -2,34 +2,31 @@
using System.Collections.Generic;
using System.Linq.Expressions;
namespace VAR.Json
namespace VAR.Json;
public static class ObjectActivator
{
public static class ObjectActivator
private static readonly Dictionary<Type, Func<object>> _creators = new();
private static Func<object> GetLambdaNew(Type type)
{
private static readonly Dictionary<Type, Func<object>> _creators = new Dictionary<Type, Func<object>>();
private static Func<object> GetLambdaNew(Type type)
lock (_creators)
{
lock (_creators)
{
if (_creators.ContainsKey(type))
{
return _creators[type];
}
if (_creators.TryGetValue(type, out Func<object>? creator)) { return creator; }
NewExpression newExp = Expression.New(type);
LambdaExpression lambda = Expression.Lambda(typeof(Func<object>), newExp);
Func<object> compiledLambdaNew = (Func<object>)lambda.Compile();
NewExpression newExp = Expression.New(type);
LambdaExpression lambda = Expression.Lambda(typeof(Func<object>), newExp);
Func<object> compiledLambdaNew = (Func<object>)lambda.Compile();
_creators.Add(type, compiledLambdaNew);
return _creators[type];
}
}
_creators.Add(type, compiledLambdaNew);
public static object CreateInstance(Type type)
{
Func<object> creator = GetLambdaNew(type);
return creator();
return _creators[type];
}
}
public static object CreateInstance(Type type)
{
Func<object> creator = GetLambdaNew(type);
return creator();
}
}

View File

@@ -1,85 +1,73 @@
namespace VAR.Json
namespace VAR.Json;
public class ParserContext
{
public class ParserContext
#region Declarations
private string _text = string.Empty;
private int _length;
private int _i;
private int _markStart;
#endregion Declarations
#region Public methods
public void SetText(string text)
{
#region Declarations
_text = text;
_length = text.Length;
_i = 0;
_markStart = 0;
}
private readonly string _text;
private readonly int _length;
private int _i;
private int _markStart;
#endregion Declarations
#region Creator
public ParserContext(string text)
{
_text = text;
_length = text.Length;
_i = 0;
_markStart = 0;
}
#endregion Creator
#region Public methods
public char SkipWhite()
{
while (_i < _length && char.IsWhiteSpace(_text[_i]))
{
_i++;
}
if (AtEnd())
{
return (char)0;
}
return _text[_i];
}
public char Next()
public char SkipWhite()
{
while (_i < _length && char.IsWhiteSpace(_text[_i]))
{
_i++;
if (AtEnd())
{
return (char)0;
}
return _text[_i];
}
public bool AtEnd()
if (AtEnd())
{
return _i >= _length;
return (char)0;
}
public void Mark()
{
_markStart = _i;
}
public string GetMarked()
{
if (_i < _length && _markStart < _length)
{
return _text.Substring(_markStart, _i - _markStart);
}
else
{
if (_markStart < _length)
{
return _text.Substring(_markStart, _length - _markStart);
}
else
{
return string.Empty;
}
}
}
#endregion Public methods
return _text[_i];
}
public char Next()
{
_i++;
if (AtEnd())
{
return (char)0;
}
return _text[_i];
}
public bool AtEnd()
{
return _i >= _length;
}
public void Mark()
{
_markStart = _i;
}
public string GetMarked()
{
if (_i < _length && _markStart < _length)
{
return _text.Substring(_markStart, _i - _markStart);
}
return _markStart < _length
? _text.Substring(_markStart, _length - _markStart)
: string.Empty;
}
#endregion Public methods
}

View File

@@ -1,9 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<OutputType>Library</OutputType>
<IsPackable>true</IsPackable>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Nullable>enable</Nullable>
<LangVersion>default</LangVersion>
</PropertyGroup>
<PropertyGroup>
<PackageId>VAR.Json</PackageId>