| Actions | NuGet |
|---|---|
A lightweight source generator library that automatically creates read-only collection wrappers for your types using the GenerateReadOnlyList attribute.
AutoCollection eliminates boilerplate code by generating IReadOnlyList<T> implementations for your collection types. This allows you to create type-safe, immutable collection wrappers without writing repetitive code.
Install the AutoCollection package via NuGet:
dotnet add package AutoCollection
AutoCollection provides a simple attribute-based API to generate read-only list implementations. There are two main ways to use this library:
Simply apply the attribute to a partial class and the source generator will create a complete implementation:
using AutoCollection;
namespace Example;
// Apply the attribute to a partial class
[GenerateReadOnlyList(typeof(string))]
public partial class SimpleStringList { }
// Usage:
var stringList = new SimpleStringList(["one", "two", "three"]);
Console.WriteLine(stringList.Count); // Outputs: 3
Console.WriteLine(stringList[0]); // Outputs: "one"You can specify a custom backing field name and provide your own constructor:
using AutoCollection;
using System.Collections.Generic;
using System.Linq;
namespace Example;
[GenerateReadOnlyList(typeof(int), nameof(_values))]
public partial class CustomIntList
{
public CustomIntList(IEnumerable<int> vals)
{
_values = vals?.ToArray() ?? throw new ArgumentNullException(nameof(vals));
}
private readonly int[] _values;
}
// Usage:
var intList = new CustomIntList([1, 2, 3]);
Console.WriteLine(intList.Count); // Outputs: 3
Console.WriteLine(intList[1]); // Outputs: 2The generator works with any type, including your own custom classes:
using AutoCollection;
namespace Example;
public class Person
{
public string FirstName { get; set; } = "John";
public string LastName { get; set; } = "Doe";
public string FullName => $"{FirstName} {LastName}";
}
[GenerateReadOnlyList(typeof(Person))]
public partial class PersonList { }
// Usage:
var people = new PersonList([new Person(), new Person()]);
Console.WriteLine(people.Count); // Outputs: 2
Console.WriteLine(people[0].FullName); // Outputs: "John Doe"using AutoCollection;
namespace Example;
// Apply the attribute to a partial class
[GenerateList(typeof(string))]
public partial class SimpleStringList { }
// Usage:
var stringList = new SimpleStringList(["one", "two", "three"]);
Console.WriteLine(stringList.Count); // Outputs: 3
Console.WriteLine(stringList[0]); // Outputs: "one"
stringList.Add("Four");
Console.WriteLine(stringList[3]); // Outputs: "four"- Zero runtime dependencies - AutoCollection runs at build time through the C# source generator feature
- Type safety - Get compile-time checking for your collections
- Customizable - Use default implementation or provide your own backing field and constructor
- Lightweight - Generates minimal code with no performance overhead
For a class like:
[GenerateReadOnlyList(typeof(string))]
public partial class SimpleStringList { }The source generator creates:
public partial class SimpleStringList : IReadOnlyList<string>
{
public SimpleStringList(IEnumerable<string> items)
{
_items = items?.ToArray() ?? throw new ArgumentNullException(nameof(items));
}
private readonly string[] _items;
public string this[int index] => _items[index];
public int Count => _items.Length;
public IEnumerator<string> GetEnumerator() => ((IEnumerable<string>)_items).GetEnumerator();
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => _items.GetEnumerator();
}- .NET 6.0 or higher
- C# 10.0 or higher
AutoCollection is licensed under the MIT License.
Contributions are welcome! Feel free to submit issues or pull requests on the GitHub repository.