Skip to content

Commit dbd2a6b

Browse files
[release/6.0] Handle parameterless ctors in structs in STJ's ReflectionEmitMemberAccessor (#67901)
* [release/6.0] backport #62989 "Handle parameterless ctors in structs in STJ's ReflectionEmitMemberAccessor" * Add explicit parameterless constructors in the tests * Update ConstructorTests.ParameterMatching.cs * address feedback Co-authored-by: Eirik Tsarpalis <[email protected]>
1 parent cc3b551 commit dbd2a6b

File tree

3 files changed

+72
-1
lines changed

3 files changed

+72
-1
lines changed

src/libraries/System.Text.Json/src/System.Text.Json.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
<Nullable>enable</Nullable>
1010
<IncludeInternalObsoleteAttribute>true</IncludeInternalObsoleteAttribute>
1111
<IsPackable>true</IsPackable>
12-
<ServicingVersion>4</ServicingVersion>
12+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
13+
<ServicingVersion>5</ServicingVersion>
1314
<PackageDescription>Provides high-performance and low-allocating types that serialize objects to JavaScript Object Notation (JSON) text and deserialize JSON text to objects, with UTF-8 support built-in. Also provides types to read and write JSON text encoded as UTF-8, and to create an in-memory document object model (DOM), that is read-only, for random access of the JSON elements within a structured view of the data.
1415

1516
Commonly Used Types:

src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionEmitMemberAccessor.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ internal sealed class ReflectionEmitMemberAccessor : MemberAccessor
4949
else
5050
{
5151
generator.Emit(OpCodes.Newobj, realMethod);
52+
if (type.IsValueType)
53+
{
54+
// Since C# 10 it's now possible to have parameterless constructors in structs
55+
generator.Emit(OpCodes.Box, type);
56+
}
5257
}
5358

5459
generator.Emit(OpCodes.Ret);

src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.ParameterMatching.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,6 +1324,71 @@ public class ClassWithIgnoredSameType
13241324
public ClassWithIgnoredSameType(ClassWithIgnoredSameType prop) { }
13251325
}
13261326

1327+
[Fact]
1328+
public void StructWithPropertyInit_DeseralizeEmptyObject()
1329+
{
1330+
string json = @"{}";
1331+
var obj = JsonSerializer.Deserialize<StructWithPropertyInit>(json);
1332+
Assert.Equal(42, obj.A);
1333+
Assert.Equal(0, obj.B);
1334+
}
1335+
1336+
[Fact]
1337+
public void StructWithPropertyInit_OverrideInitedProperty()
1338+
{
1339+
string json = @"{""A"":43}";
1340+
var obj = JsonSerializer.Deserialize<StructWithPropertyInit>(json);
1341+
Assert.Equal(43, obj.A);
1342+
Assert.Equal(0, obj.B);
1343+
1344+
json = @"{""A"":0,""B"":44}";
1345+
obj = JsonSerializer.Deserialize<StructWithPropertyInit>(json);
1346+
Assert.Equal(0, obj.A);
1347+
Assert.Equal(44, obj.B);
1348+
1349+
json = @"{""B"":45}";
1350+
obj = JsonSerializer.Deserialize<StructWithPropertyInit>(json);
1351+
Assert.Equal(42, obj.A); // JSON doesn't set A property so it's expected to be 42
1352+
Assert.Equal(45, obj.B);
1353+
}
1354+
1355+
public struct StructWithPropertyInit
1356+
{
1357+
public StructWithPropertyInit() {}
1358+
public long A { get; set; } = 42;
1359+
public long B { get; set; } = 0;
1360+
}
1361+
1362+
[Fact]
1363+
public void StructWithFieldInit_DeseralizeEmptyObject()
1364+
{
1365+
string json = @"{}";
1366+
var obj = JsonSerializer.Deserialize<StructWithFieldInit>(json);
1367+
Assert.Equal(0, obj.A);
1368+
Assert.Equal(42, obj.B);
1369+
}
1370+
1371+
public struct StructWithFieldInit
1372+
{
1373+
public StructWithFieldInit() {}
1374+
public long A = 0;
1375+
public long B = 42;
1376+
}
1377+
1378+
[Fact]
1379+
public void StructWithExplicitParameterlessCtor_DeseralizeEmptyObject()
1380+
{
1381+
string json = @"{}";
1382+
var obj = JsonSerializer.Deserialize<StructWithExplicitParameterlessCtor>(json);
1383+
Assert.Equal(42, obj.A);
1384+
}
1385+
1386+
public struct StructWithExplicitParameterlessCtor
1387+
{
1388+
public long A;
1389+
public StructWithExplicitParameterlessCtor() => A = 42;
1390+
}
1391+
13271392
public async Task TestClassWithDefaultCtorParams()
13281393
{
13291394
ClassWithDefaultCtorParams obj = new ClassWithDefaultCtorParams(

0 commit comments

Comments
 (0)