-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
[API Proposal]: Add json option to fallback to parsing value from string if type implements IParsable/ISpanParsable
and enable it by default
#88206
Comments
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis Issue DetailsBackground and motivationCurrently json parsing already handles some string parsing scenarios for some tipes, e.g. var json = """
{
"Delay": "00:05:00"
}
""";
var obj = JsonSerializer.Deserialize<MyClass>(json);
Console.WriteLine(obj.Delay);
class MyClass
{
public TimeSpan Delay { get; set; }
} This code doesn't throw and outputs However, in more general case, where I have my own object, that implements using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
var json1 = """
{
"MyValue": {
"Value": 2
}
}
""";
var json2 = """
{
"MyValue": "2"
}
""";
var mc1 = JsonSerializer.Deserialize<MyClass1>(json1);
var mc2 = JsonSerializer.Deserialize<MyClass1>(json2);
Console.WriteLine(mc1!.MyValue.Value);
Console.WriteLine(mc2!.MyValue.Value);
class MyClass1
{
public required MyClass MyValue { get; set; }
}
class MyClass : IParsable<MyClass>
{
public int Value { get; set; }
public static MyClass Parse(string s, IFormatProvider? provider)
=> new() { Value = int.Parse(s, provider) };
public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out MyClass result)
{
if (!int.TryParse(s, out var val))
{
result = default;
return false;
}
result = new() { Value = val };
return true;
}
} I expect 2 outputs of Such capability will also enable currenctly unsupported parsing scenarios when type has several constructors and there is no parameterless one among them. In such cases if type implements API ProposalInstead of treating namespace System.Text.Json;
public sealed class JsonSerializerOptions
{
public bool FallbackToParsingFromString { get; set; } = true; // I believe name can be improved
} This way we keep previous behavior and enable new scenarios with custom parsable types. API UsageSince the flag should be on by default, my code example from above should start to work. However, I can disable this flag to get the error again: using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
var json1 = """
{
"MyValue": {
"Value": 2
}
}
""";
var json2 = """
{
"MyValue": "2"
}
""";
var options = new JsonSerializerOptions
{
FallbackToParsingFromString = false
};
var mc1 = JsonSerializer.Deserialize<MyClass1>(json1, options); // Still works
var mc2 = JsonSerializer.Deserialize<MyClass1>(json2, options); // Exception thrown here
Console.WriteLine(mc1!.MyValue.Value);
Console.WriteLine(mc2!.MyValue.Value);
class MyClass1
{
public required MyClass MyValue { get; set; }
}
class MyClass : IParsable<MyClass>
{
public int Value { get; set; }
public static MyClass Parse(string s, IFormatProvider? provider)
=> new() { Value = int.Parse(s, provider) };
public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out MyClass result)
{
if (!int.TryParse(s, out var val))
{
result = default;
return false;
}
result = new() { Value = val };
return true;
}
} Alternative Designs
RisksNo response
|
What about |
Would this automatically support numeric types encoded as strings as well? I'm not sure that's desirable default behavior. (It certainly isn't for my applications, but others have requested it.) |
Duplicate of #86529. We should instead focus on Echoing @gregsdennis's comment though I don't think we should default to these interfaces if implemented, since it's not likely that they will have been implemented with JSON serialization in mind. In the future it's more likely we could rely purpose-built interfaces such as public interface IJsonSerializable<T>
{
static abstract void Serialize(Utf8JsonWriter writer, T? value);
}
public interface IJsonDeserializable<T>
{
static abstract T? Serialize(ref Utf8JsonReader reader);
} or simply public interface IJsonSerializable<T>
{
static abstract JsonConverter<T> GetConverter(JsonSerializerOptions options);
} |
Background and motivation
Currently json parsing already handles some string parsing scenarios for some tipes, e.g.
TimeSpan
:This code doesn't throw and outputs
00:05:00
as expected.However, in more general case, where I have my own object, that implements
IParsable
/ISpanParsable
the same trick fails:I expect 2 outputs of
2
to the console, but actually get a parse error in the second case.Such capability will also enable currenctly unsupported parsing scenarios when type has several constructors and there is no parameterless one among them. In such cases if type implements
IParsable
/ISpanParsable
and in the given json corresponding proeprty is a string,JsonSerializer
can fallback to this code path as well.API Proposal
Instead of treating
TimeSpan
and similar build-in types as "special" during json parsing, we can haveJsonSerializerOptionsFlag
, that controlls fallbacks to string parsing and set it totrue
by default:This way we keep previous behavior and enable new scenarios with custom parsable types.
API Usage
Since the flag should be on by default, my code example from above should start to work. However, I can disable this flag to get the error again:
Alternative Designs
OnlyFullObject
,CanFallbackToStringParse
,OnlyAllowStringParse
(not final names ofc.)Risks
No response
The text was updated successfully, but these errors were encountered: