Home > Software design >  Which C# language feature allows initializing a property that only provides a get implementation?
Which C# language feature allows initializing a property that only provides a get implementation?

Time:10-31

I'm working with the System.Text.Json serializer, and need to provide custom serialization logic for one property of my overall object. That's not the issue, it's working, but I don't understand how. This is the sample provided in the MS docs.

Hover description in VSCode

Here's the decompiled code I get with a Go To Definition.

        // Summary:
        //     Gets the list of user-defined converters that were registered.
        //
        // Returns:
        //     The list of custom converters.
        public IList<Serialization.JsonConverter> Converters { get; }

And, what I think is the original code.

https://github.com/dotnet/runtime/blob/main/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs#L23

What magick explains this?

CodePudding user response:

It's a collection initializer.

Converters is a collection. In the following code:

Converters =
{
    new DateTimeOffsetJsonConverter()
}

You're not assigning to Converters itself. Since the type of Converters is a type that implements IEnumerable and has an Add method with the appropriate signature, the compiler simply generates code that calls that Add method and passes it your DateTimeOffsetJsonConverter instance. The Converters property itself does not need a setter because you only need the collection itself.

The fact that it looks like assignment is just a quirk of the grammar.

CodePudding user response:

It's being done through the collection initializers.

Collection initializers let you specify one or more element initializers when you initialize a collection type that implements IEnumerable and has Add with the appropriate signature as an instance method or an extension method. The element initializers can be a simple value, an expression, or an object initializer. By using a collection initializer, you do not have to specify multiple calls; the compiler adds the calls automatically.

While the property itself has only a getter. The instance behind the getter implements IEnumerable<T> and also has an .Add() method.

So your code is just syntactic sugar for something like this:

var serializeOptions = new JsonSerializerOptions;
serializeOptions.Converters.Add(new DateTimeOffsetJsonConverter());

CodePudding user response:

It's just a basic Collection initializers.

Collection initializers let you specify one or more element initializers when you initialize a collection type that implements IEnumerable and has Add with the appropriate signature as an instance method or an extension method. The element initializers can be a simple value, an expression, or an object initializer. By using a collection initializer, you do not have to specify multiple calls; the compiler adds the calls automatically.

var names = new List<string> {
    "Alice", "Bob", "Curtis", "David"
};

// Equivalent to

var names = new List<string>();
names.Add("Alice");
names.Add("Bob");
names.Add("Curtis");
names.Add("David");

It's possible to use on get only property :

public class Book
{
    public IList<string> Names { get; } = new List<string> { "Alice", "Bob" };
}


var book = new Book {
    Names = { "Curtis", "David" }
};

// Equivalent to
var book = new Book();
book.Names.Add("Curtis");
book.Names.Add("David");
  • Related