-
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
System.Text.Json constructor deserializing with covariant return type read-only properties sets values to null #56999
Comments
Tagging subscribers to this area: @eiriktsarpalis, @layomia Issue DetailsDescriptionI would expect the below to work, however it does not. Maybe because covariant return types are new and not yet handled in System.Text.Json yet. I think the example speaks for itself but let me know if more information is required. Configuration
Non-working ExampleUsing covariant return type read-only properties passed through derived constructor does not work. using System;
using System.Text.Json;
using System.Text.Json.Serialization;
public class Program
{
public static void Main()
{
var json = "{ \"prop\": { \"id\": \"abc\", \"num\": 2 } }";
var obj = JsonSerializer.Deserialize<DerivedClass>(json);
Console.WriteLine(obj?.Property?.Id ?? "null");
Console.WriteLine(obj?.Property?.Number?.ToString() ?? "null");
}
public class BaseClass
{
public BaseClass(BaseProperty property)
{
Property = property;
}
[JsonPropertyName("prop")]
public virtual BaseProperty Property { get; }
}
public class DerivedClass : BaseClass
{
public DerivedClass(DerivedProperty property)
: base(property)
{
}
public override DerivedProperty Property { get; }
}
public class BaseProperty
{
[JsonPropertyName("id")]
public string Id { get; set; }
}
public class DerivedProperty : BaseProperty
{
[JsonPropertyName("num")]
public int? Number { get; set; }
}
} Output:
Working ExampleUsing non-covariant return type read-only properties passed through derived constructor does work: using System;
using System.Text.Json;
using System.Text.Json.Serialization;
public class Program
{
public static void Main()
{
var json = "{ \"prop\": { \"id\": \"abc\", \"num\": 2 } }";
var obj = JsonSerializer.Deserialize<DerivedClass>(json);
Console.WriteLine(obj?.Property?.Id ?? "null");
}
public class BaseClass
{
public BaseClass(BaseProperty property)
{
Property = property;
}
[JsonPropertyName("prop")]
public virtual BaseProperty Property { get; }
}
public class DerivedClass : BaseClass
{
public DerivedClass(BasePropertyproperty)
: base(property)
{
}
}
public class BaseProperty
{
[JsonPropertyName("id")]
public string Id { get; set; }
}
} Output:
|
I can reproduce; when I change the code to specify a non-covariant override then the serializer would throw the exception: Unhandled exception. System.InvalidOperationException: Members 'Property' and 'Property' on type 'Program+NonCovariantReturnDerivedClass' cannot both bind with parameter 'property' in constructor 'Void .ctor(System.Object)' on deserialization. I was not able to produce a workaround that didn't involve renaming the base property. cc @layomia Minimal reproduction: using System;
using System.Text.Json;
using System.Text.Json.Serialization;
public class Program
{
public static void Main()
{
var json = "{ \"prop\": \"value\" }";
var obj = JsonSerializer.Deserialize<BaseClass>(json);
Console.WriteLine(obj.Property is not null); // True
obj = JsonSerializer.Deserialize<CovariantReturnDerivedClass>(json);
Console.WriteLine(obj.Property is not null); // False
// Unhandled exception. System.InvalidOperationException: Members 'Property' and 'Property' on type 'Program+NonCovariantReturnDerivedClass'
// cannot both bind with parameter 'property' in constructor 'Void .ctor(System.Object)' on deserialization.
obj = JsonSerializer.Deserialize<DerivedClass>(json);
}
public class BaseClass
{
public BaseClass(object property)
{
Property = property;
}
[JsonPropertyName("prop")]
public virtual object Property { get; }
}
public class CovariantReturnDerivedClass : BaseClass
{
public CovariantReturnDerivedClass(string property)
: base(property)
{
}
public override string Property { get; }
}
public class DerivedClass : BaseClass
{
public DerivedClass(object property)
: base(property)
{
}
public override object Property { get; }
}
} |
Related to #46522. |
We should address as part of #44428. |
Description
I would expect the below to work, however it does not. Maybe because covariant return types are new and not yet handled in System.Text.Json yet. I think the example speaks for itself but let me know if more information is required.
Configuration
Non-working Example
Using covariant return type read-only properties passed through derived constructor does not work.
https://dotnetfiddle.net/IsNX3q
Output:
Working Example
Using non-covariant return type read-only properties passed through derived constructor does work:
Output:
The text was updated successfully, but these errors were encountered: