0

I have the following code:

public abstract class Base
{
}

public class Foo : Base
{
}

public class Bar : Base
{
}

public static void TestA()
{
    JsonPolymorphismOptions options = new JsonPolymorphismOptions
    {
        DerivedTypes =
        {
            new JsonDerivedType(typeof(Foo), nameof(Foo)),
            new JsonDerivedType(typeof(Bar), nameof(Bar)),
        }
    };
}

It compiles just fine.

However, the following code does not compile:

public static void TestB()
{
    IList<JsonDerivedType> subtypes = new List<JsonDerivedType>()
    {
        new JsonDerivedType(typeof(Foo), nameof(Foo)),
        new JsonDerivedType(typeof(Bar), nameof(Bar)),
    };


    JsonPolymorphismOptions options = new JsonPolymorphismOptions
    {
        DerivedTypes = subtypes
    };
}

I get a

Error CS0200 Property or indexer 'JsonPolymorphismOptions.DerivedTypes' cannot be assigned to -- it is read only

Well, I can obviously assign it in the first initializer in TestA, why not in TestB? And is there a way to assign a previously assembled list to the DerivedTypes property in TestB without hard-coding it?

I assume the problem is not related to System.Text.Json.Serialization.Metadata.JsonPolymorphismOptions but rather to my general usage of initializer syntax.

Joerg
  • 790
  • 2
  • 10
  • 23

3 Answers3

4

Well, I can obviously assign it in the first initializer in TestA

No, you can't. That's not what the initializer does.

This code:

JsonPolymorphismOptions options = new JsonPolymorphismOptions
{
    DerivedTypes =
    {
        new JsonDerivedType(typeof(Foo), nameof(Foo)),
        new JsonDerivedType(typeof(Bar), nameof(Bar)),
    }
};

... is equivalent to:

JsonPolymorphismOptions options = new JsonPolymorphismOptions();
options.DerivedTypes.Add(new JsonDerivedType(typeof(Foo), nameof(Foo)));
options.DerivedTypes.Add(new JsonDerivedType(typeof(Bar), nameof(Bar)));

That's how collection initializers work.

To add the members of an existing list, you can use:

JsonPolymorphismOptions options = new JsonPolymorphismOptions();
foreach (var type in subtypes)
{
   options.DerivedTypes.Add(type);
}

You could potentially create an AddRange extension method on IList<T>, allowing you to write:

JsonPolymorphismOptions options = new JsonPolymorphismOptions();
options.DerivedTypes.AddRange(subtypes);

Note that in both cases, the original list ends up being independent from the list exposed by options.DerivedTypes - if you call subtypes.Add(...) afterwards, options.DerivedTypes will not be affected.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I was totally unaware of the inner working of collection initializers and their `Add()` call chain. That was very helpful. Thanks for pointing it out. – Joerg Mar 21 '23 at 09:05
0

It looks like TestA() is adding elements to DerivedTypes and TestB() is giving it a new object

SKYC
  • 33
  • 6
0

This is a way to assign a previously assembled list

    var subtypes = new[]
        {
        new JsonDerivedType(typeof(Foo), nameof(Foo)),
        new JsonDerivedType(typeof(Bar), nameof(Bar)),
    };

    TestB(subtypes);

method

public static void TestB(IEnumerable<JsonDerivedType> subtypes)
{
    JsonPolymorphismOptions options = new JsonPolymorphismOptions();

    foreach (var subtype in subtypes)
        options.DerivedTypes.Add(subtype);
}
Serge
  • 40,935
  • 4
  • 18
  • 45