This document summarizes the proposed parts of Collection Literals we would like to ship in C# 12. It separates out the proposal into parts we strongly feel should be in the initial release, and parts which could potentially come later.
-
Target-typing collection expressions for the following sequence-like types:
-
Span<T>
-
T[]
-
Types supporting collection initializers (like
List<T>
,HashSet<T>
etc.) -
Interfaces implemented by
List<T>
(likeIEnumerable<string>
, etc.) -
Types supporting a new
Construct
creation path (used for types likeImmutableArray<T>
). Note: this may be at risk as it will require work with runtime to define pattern/attributes to support this. See Optional Pieces for more details on this.
-
-
Target-typing collection literals for map-like types.
- Map-like types supporting
collection initializersAdd
semantics, oroverwrite
semantics?
- Interfaces implemented by
Dictionary<TKey, TValue>
ImmutableDictionary<K,V>
- Map-like types supporting
-
Supporting spread elemements (
.. expr
) for both sequence and map-like collection expressions. -
Natural-typing
-
non-empty, non-dictionary collection literals to
List<T>
(using best-common-type algorithm on element types). -
non-empty, dictionary collection literals to
Dictionary<TKey,TValue>
. -
Mutable
List<T>/Dictionary<TKey,TValue>
chosen to support the widest set of use cases and users. This is intended for within a method, and for places where people are using 'var' and already expect to be able to build up and manipulate things. -
Performance concerns around cost of
List<T>
handled in Optional Pieces. -
Empty list/dictionary listerals handled in Optional Pieces.
-
-
New
Construct
path for creating special types. Needs design with Runtime. With the methods either on the type, or found through some special attribute. Compiler calls into method to initialize space, then gets the Span it copies the values into. This would allow types likeImmutableArray<T>
(or proposed futureValueList<T>
types) to act like acollection initializer
when the capacity could be predetermined. This may be a family of methods. For example:-
public static List<T> Create<T>(int count, int capacity, out Span<T> span);
-
public static ImmutableArray<T> Create<T>(int count, out Span<T> span);
-
public ValueListBuilder<T>(Span<T> buffer, int count);
-
It would be desirable to prefer these paths over the collection-initializer path.
List<T>
, for example, would be much faster to initialize in this form, versus repeated.Add
calls.
-
-
Optimizations around fresh
List<T>
instances. It would be nice if collection literals could be used within a method-body without unnecessary overhead when not desirable. For example:var v = [GetA(), GetB(), GetC()]; // or even: List<Something> v = new List<Something>() { GetA(), GetB(), GetC() }; foreach (var string in v)
This should ideally be stack-alloced without the multiple heap allocations that
List<T>
incurs.List<T>
Performance covers a proposal for how this would work, transparently speeding up existing applications, while also making it more palatable for performance conscious users to use collection literals. -
Supporting natural types for empty collection literals. e.g.
var v = [];
. This is challenging due to the lack of any information in the initializer of thevar
to provide type information.-
This may be something we never support (due to being too complex). However,
-
Inferred Generic Type proposes a supported way to handle this situation. Namely through the introduction of 'partially inferred generics' like
List<_>
, wherevar v = [];
would be equivalent toList<_> v = new List<_>();
. In this system, the outer type is concretely known, while the instantiation is determined based on the usage of the variable later in the method. For example, callingv.Add(0)
would contribute to inferring the variable type to beList<int>
. -
We would likely need a special syntax for empty dictionary literals in this case. For example:
var v = [:];
.
-