-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Support constructors with byref parameters (in/ref/out) in System.Text.Json #122950
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 5 commits
0cd298b
185a1fe
55d3b03
eec5b88
34a2088
316c65d
2509f8c
c3a2b48
7d164fd
4f8089e
7de1ab7
45e9b72
f544feb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1841,5 +1841,83 @@ public class ClassWithRequiredProperty | |||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| public required string? Bar { get; set; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| [Fact] | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async Task DeserializeType_WithInParameters() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| string json = @"{""DateTime"":""2020-12-15T00:00:00"",""TimeSpan"":""01:02:03""}"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| TypeWith_InParameters result = await Serializer.DeserializeWrapper<TypeWith_InParameters>(json); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal(new DateTime(2020, 12, 15), result.DateTime); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal(new TimeSpan(1, 2, 3), result.TimeSpan); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| public class TypeWith_InParameters | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| public TypeWith_InParameters(in DateTime dateTime, in TimeSpan timeSpan) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| DateTime = dateTime; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| TimeSpan = timeSpan; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| public DateTime DateTime { get; set; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| public TimeSpan TimeSpan { get; set; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| [Fact] | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async Task DeserializeType_WithMixedByRefParameters() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| string json = @"{""Value1"":42,""Value2"":""hello"",""Value3"":3.14,""Value4"":true}"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| TypeWith_MixedByRefParameters result = await Serializer.DeserializeWrapper<TypeWith_MixedByRefParameters>(json); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal(42, result.Value1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal("hello", result.Value2); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal(3.14, result.Value3); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.True(result.Value4); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| public class TypeWith_MixedByRefParameters | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| public TypeWith_MixedByRefParameters(in int value1, string value2, in double value3, bool value4) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Value1 = value1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Value2 = value2; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Value3 = value3; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Value4 = value4; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| public int Value1 { get; set; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| public string Value2 { get; set; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| public double Value3 { get; set; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| public bool Value4 { get; set; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| [Fact] | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async Task DeserializeType_WithLargeInParameters() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| string json = @"{""A"":1,""B"":2,""C"":3,""D"":4,""E"":5}"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| TypeWith_LargeInParameters result = await Serializer.DeserializeWrapper<TypeWith_LargeInParameters>(json); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal(1, result.A); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal(2, result.B); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal(3, result.C); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal(4, result.D); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal(5, result.E); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| public class TypeWith_LargeInParameters | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| public TypeWith_LargeInParameters(in int a, in int b, in int c, in int d, in int e) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @copilot please add tests covering all possible permutations of
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added in c3a2b48. Tests now cover all permutations of
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @copilot make sure the test matrix as visualized above has been updated.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated in 7d164fd. The test matrix now shows all tests passing for both reflection and source generation:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| A = a; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| B = b; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| C = c; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| D = d; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| E = e; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| public int A { get; set; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| public int B { get; set; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| public int C { get; set; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| public int D { get; set; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| public int E { get; set; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot, are there tests covering in, out, and ref?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tests currently cover
inparameters only. I investigated adding tests forrefandout:ref: Requires source generator changes to emitrefkeyword at call sites (currently generatesnew Type(arg1, arg2)but needsnew Type(ref arg1, ref arg2))out: Not meaningful for deserialization -outparameters provide output, not input, so the caller can't provide values from JSONThe
inkeyword is the most common use case and works because it doesn't require a keyword at call sites (it's the callee that specifiesin). Support forrefparameters would require a separate change to the source generator.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot can you add tests for ref and out that at least lock in the current behaviors, rather than leaking them totally untested?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added in 316c65d. The tests lock in current behavior:
ref: Works with reflection, skipped for source gen (would needrefkeyword at call sites)out: Constructor receives default values (99, "default") sinceoutis for output, not input. Test verifies this expected limitation.