Skip to content

Problem with the Collection builder example #41756

Open
@RexJaeschke

Description

@RexJaeschke

Type of issue

Code doesn't work

Description

I'm writing the spec for the "collections expressions" feature for the Ecma C# standard, and used your tutorial to get up to speed on this topic. While playing with your Collection builder example I found a shortcoming. Regardless of how many elements are in the collection expression, the result returned is a collection of 80, based on the fixed size of the char array allocated. Specifically, for a collection expression with 3 elements, one would expect the type's Count or Length property to be 3, but on enumeration, one gets 80 elements. As such, the type is not well-behaved, so is not the best example in that regard. You write

Collection expressions work with any collection type that's well-behaved. A well-behaved collection has the following characteristics:

  • The value of Count or Length on a countable collection produces the same value as the number of elements when enumerated.
  • ...

Here is my test; it fixes this problem; it adds a Count property and an indexer, and it's generic.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Xml.Linq;

MyCollection<char> coll1 = ['t', 'e', 'x', 't'];
DisplayCollection("coll1", coll1);
Console.WriteLine($"coll1[1] = >{coll1[1]}<");
coll1[2] = '?';
DisplayCollection("coll1", coll1);

MyCollection<ValueType> coll2 = [7, 6.5, 'x', 123L];
DisplayCollection("coll2", coll2);

MyCollection<object> coll3 = ["abc", 100, 10.5];
DisplayCollection("coll3", coll3);

MyCollection<object> coll4 = [];
DisplayCollection("coll4", coll4);

MyCollection<object> coll5 = [10, "xyz", ..coll2];
DisplayCollection("coll5", coll5);

static void DisplayCollection<T>(string collName, MyCollection<T> coll)
{
    Console.Write($"{collName}'s Count = {coll.Count}: ");
    foreach (var element in coll)
    {
        Console.Write($" {element}");
    }
    Console.WriteLine();
}

[CollectionBuilder(typeof(MyCollectionBuilder), "Create")]
public class MyCollection<T> : IEnumerable<T>
{
    private readonly T[] _storage;
    public int Count { get; }
    public T this[int index]
    {
        get
        {
            return _storage[index];
        }

        set
        {
            _storage[index] = value;
        }
    }
    public MyCollection(ReadOnlySpan<T> elements)
    {
        Count = elements.Length;
        _storage = new T[Count];
        for (int i = 0; i < Count; i++)
        {
            _storage[i] = elements[i];
        }
    }
    public IEnumerator<T> GetEnumerator() => _storage.AsEnumerable<T>().GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => _storage.GetEnumerator();
}
internal static class MyCollectionBuilder
{
    internal static MyCollection<T> Create<T>(ReadOnlySpan<T> values) => new MyCollection<T>(values);
}

Page URL

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/collection-expressions

Content source URL

https://github.com/dotnet/docs/blob/main/docs/csharp/language-reference/operators/collection-expressions.md

Document Version Independent Id

49349466-94fd-00b5-93da-e4200d9f9ec8

Article author

@BillWagner

Metadata

  • ID: 63733f9f-0896-c948-1a7e-58fb428c11c0
  • Service: dotnet-csharp
  • Sub-service: lang-reference

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions