From cdaf9994b9c28f682e21fcd1ffbf2943783bbea0 Mon Sep 17 00:00:00 2001 From: Vladimir Pecanac Date: Sat, 17 Oct 2026 23:56:43 +0200 Subject: [PATCH] IEnumerable in C#: retarget net10.0, Book record, GenericLibrary with yield return, LibraryTests Both projects net7.0 to net10.0. Microsoft.NET.Test.Sdk 18.11.0, xunit 2.9.3, xunit.runner.visualstudio 4.0.1, coverlet.collector 10.1.0. Book becomes a positional record, the Library constructor copies with a collection expression, Program.cs moves to top-level statements and gains the GenericLibrary query, file-scoped namespaces. New GenericLibrary implements IEnumerable with yield return. The test project references the console project and gains LibraryTests (iteration order from the -1 start, Cast before LINQ on the non-generic Library, LINQ directly on GenericLibrary, Reset on the generated enumerator throws NotSupportedException). --- .../IEnumerableCSharp/Book.cs | 15 +----- .../IEnumerableCSharp/BookEnumerator.cs | 47 +++++++++-------- .../IEnumerableCSharp/GenericLibrary.cs | 23 +++++++++ .../IEnumerableCSharp.csproj | 2 +- .../IEnumerableCSharp/Library.cs | 27 ++++------ .../IEnumerableCSharp/Program.cs | 44 ++++++++-------- .../IEnumerableCSharp/Tests/LibraryTests.cs | 51 +++++++++++++++++++ .../IEnumerableCSharp/Tests/Tests.csproj | 14 +++-- 8 files changed, 142 insertions(+), 81 deletions(-) create mode 100644 collections-csharp/IEnumerableCSharp/IEnumerableCSharp/GenericLibrary.cs create mode 100644 collections-csharp/IEnumerableCSharp/Tests/LibraryTests.cs diff --git a/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/Book.cs b/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/Book.cs index 86a6c4b5ce..848dadc9ec 100644 --- a/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/Book.cs +++ b/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/Book.cs @@ -1,14 +1,3 @@ -namespace IEnumerableCSharp -{ - public class Book - { - public Book(string name, string author) - { - Name = name; - Author = author; - } +namespace IEnumerableCSharp; - public string Name { get; set; } - public string Author { get; set; } - } -} +public record Book(string Name, string Author); diff --git a/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/BookEnumerator.cs b/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/BookEnumerator.cs index e6cd0e59bf..4d06931b7c 100644 --- a/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/BookEnumerator.cs +++ b/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/BookEnumerator.cs @@ -1,36 +1,35 @@ using System.Collections; -namespace IEnumerableCSharp +namespace IEnumerableCSharp; + +public class BookEnumerator : IEnumerator { - public class BookEnumerator : IEnumerator - { - private readonly Book[] _books; - private int _index = -1; + private readonly Book[] _books; + private int _index = -1; - public BookEnumerator(Book[] books) - { - _books = books; - } + public BookEnumerator(Book[] books) + { + _books = books; + } - public Book Current + public Book Current + { + get { - get - { - return _books[_index]; - } + return _books[_index]; } + } - object IEnumerator.Current => Current; + object IEnumerator.Current => Current; - public bool MoveNext() - { - _index++; - return _index < _books.Length; - } + public bool MoveNext() + { + _index++; + return _index < _books.Length; + } - public void Reset() - { - _index = -1; - } + public void Reset() + { + _index = -1; } } diff --git a/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/GenericLibrary.cs b/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/GenericLibrary.cs new file mode 100644 index 0000000000..430fc5a22d --- /dev/null +++ b/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/GenericLibrary.cs @@ -0,0 +1,23 @@ +using System.Collections; + +namespace IEnumerableCSharp; + +public class GenericLibrary : IEnumerable +{ + private readonly Book[] _books; + + public GenericLibrary(Book[] books) + { + _books = [.. books]; + } + + public IEnumerator GetEnumerator() + { + foreach (var book in _books) + { + yield return book; + } + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} diff --git a/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/IEnumerableCSharp.csproj b/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/IEnumerableCSharp.csproj index f02677bf64..dfb40caafc 100644 --- a/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/IEnumerableCSharp.csproj +++ b/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/IEnumerableCSharp.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net10.0 enable enable diff --git a/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/Library.cs b/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/Library.cs index fd08b2e7af..8bd1ce95f0 100644 --- a/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/Library.cs +++ b/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/Library.cs @@ -1,24 +1,17 @@ using System.Collections; -namespace IEnumerableCSharp +namespace IEnumerableCSharp; + +public class Library : IEnumerable { - public class Library : IEnumerable - { - private readonly Book[] _books; + private readonly Book[] _books; - public Library(Book[] books) - { - _books = new Book[books.Length]; + public Library(Book[] books) + { + _books = [.. books]; + } - for (int i = 0; i < books.Length; i++) - { - _books[i] = books[i]; - } - } + public BookEnumerator GetEnumerator() => new BookEnumerator(_books); - public BookEnumerator GetEnumerator() => new BookEnumerator(_books); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } diff --git a/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/Program.cs b/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/Program.cs index fc87cd59d7..d0af06b1f5 100644 --- a/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/Program.cs +++ b/collections-csharp/IEnumerableCSharp/IEnumerableCSharp/Program.cs @@ -1,24 +1,26 @@ -namespace IEnumerableCSharp +using IEnumerableCSharp; + +Book[] books = +[ + new("Anna Karenina", "Leo Tolstoy"), + new("To Kill a Mockingbird", "Harper Lee"), + new("The Great Gatsby", "F. Scott Fitzgerald"), + new("One Hundred Years of Solitude", "Gabriel García Márquez"), + new("A Passage to India", "E.M. Forster") +]; + +var library = new Library(books); + +foreach (var book in library) { - internal class Program - { - static void Main(string[] args) - { - var books = new Book[5] - { - new Book("Anna Karenina", "Leo Tolstoy"), - new Book("To Kill a Mockingbird", "Harper Lee"), - new Book("The Great Gatsby", "F. Scott Fitzgerald"), - new Book("One Hundred Years of Solitude", "Gabriel García Márquez"), - new Book("A Passage to India", "E.M. Forster") - }; + Console.WriteLine($"Book: {book.Name}, Author: {book.Author}"); +} - var library = new Library(books); +var genericLibrary = new GenericLibrary(books); - foreach (var book in library) - { - Console.WriteLine($"Book: {book.Name}, Author: {book.Author}"); - } - } - } -} \ No newline at end of file +var tolstoy = genericLibrary.Where(book => book.Author == "Leo Tolstoy"); + +foreach (var book in tolstoy) +{ + Console.WriteLine($"By Tolstoy: {book.Name}"); +} diff --git a/collections-csharp/IEnumerableCSharp/Tests/LibraryTests.cs b/collections-csharp/IEnumerableCSharp/Tests/LibraryTests.cs new file mode 100644 index 0000000000..8abb73e597 --- /dev/null +++ b/collections-csharp/IEnumerableCSharp/Tests/LibraryTests.cs @@ -0,0 +1,51 @@ +using System.Collections; +using IEnumerableCSharp; + +namespace Tests; + +public class LibraryTests +{ + private static readonly Book[] Books = + [ + new("Anna Karenina", "Leo Tolstoy"), + new("To Kill a Mockingbird", "Harper Lee"), + new("War and Peace", "Leo Tolstoy") + ]; + + [Fact] + public void WhenIteratingLibrary_ThenEveryBookComesBackInOrder() + { + var names = new List(); + + foreach (var book in new Library(Books)) + { + names.Add(book.Name); + } + + Assert.Equal(["Anna Karenina", "To Kill a Mockingbird", "War and Peace"], names); + } + + [Fact] + public void WhenUsingLinqOnNonGenericLibrary_ThenCastIsNeeded() + { + var tolstoy = new Library(Books).Cast().Where(book => book.Author == "Leo Tolstoy"); + + Assert.Equal(2, tolstoy.Count()); + } + + [Fact] + public void WhenUsingLinqOnGenericLibrary_ThenNoCastIsNeeded() + { + var tolstoy = new GenericLibrary(Books).Where(book => book.Author == "Leo Tolstoy"); + + Assert.Equal(2, tolstoy.Count()); + } + + [Fact] + public void WhenResettingIteratorEnumerator_ThenNotSupportedExceptionIsThrown() + { + using var enumerator = new GenericLibrary(Books).GetEnumerator(); + + Assert.Throws(() => enumerator.Reset()); + } +} diff --git a/collections-csharp/IEnumerableCSharp/Tests/Tests.csproj b/collections-csharp/IEnumerableCSharp/Tests/Tests.csproj index ae73e6e037..520535c4a3 100644 --- a/collections-csharp/IEnumerableCSharp/Tests/Tests.csproj +++ b/collections-csharp/IEnumerableCSharp/Tests/Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net10.0 enable enable @@ -9,16 +9,20 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all + + + +