Implementing IEnumerable<T>

RRotor2/15/2023
Hi all!

I'm trying to simplify a complex return type that I have to repeat in a lot of places

Result<IEnumerable<Result<TRow, Faults<TDataFault>>>, Faults<TMetadatFault>>

Although I'm pleased with how the type allows me to easily package and aggregate errors that I encounter without having to throw and catch them, the length of the type does no favours to the code's readability.

I sought to start to simplify the type a bit by contracting
IEnumerable<Result<TRow, Faults<TDataFault>>>
down to
IRowSeq<TRow, TDataFault>

Which I tried to implement using the following code
internal interface IRowSeq<TRow, TDataFault>
    : IEnumerable<Result<TRow, Faults<TDataFault>>>
    where TRow : IRowType
    where TDataFault : Enum
{

    public new IEnumerator<Result<TRow, Faults<TDataFault>>> GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() =>
        this.GetEnumerator();
}


Although the code compiles, once I started to update the code I use to generate an IEnumerable
    private static IRowSeq<TRow, TDataFault> GetRows(ExcelData excelData)
    {
        ulong rowNumber = 1;
        
        foreach (var row in excelData.Rows.Skip(1)) // By this point in the code the header has been confirmed
        {
            yield return ParseAndValidateCells(excelData, row, rowNumber);

            rowNumber++;
        }
    }


Then I hit csharp(CS1624) - the body of (method) cannot be an iterator block because 'IRowSeq<TRow, TDataFault>' is not an iterator interface type

Perhaps I'm looking at this problem from the wrong angle. Could somebody please set me right?
TTvde12/15/2023
you can only use yield when your method returns an IEnumerable (<T>) or IAsyncEnumerable (<T>)
TTvde12/15/2023
because it creates a class under the hood which implements just IEnumerable and IEnumerator
RRotor2/15/2023
It seems strange to me that it specifically needs to be IEnumerable when an interface implementing IEnumerable should be functionally identical for the purposes of yield
TTvde12/15/2023
any other interface might contain additional methods that must be implemented, which the generated Enumerable can't
RRotor2/15/2023
Aha yes that makes sense
TTvde12/15/2023
there could possibly be a check that checks if the interface is ONLY an IEnumerable, then it could pass, but that was never added
RRotor2/15/2023
In that case do you have any suggestions for how I might start to wrap up this long return type without adding too much boilerplate code responsible for wrapping and unwrapping the data?
Tthinker2272/15/2023
(IEnumerator<T> as well)
RRotor2/15/2023
CSharp could really use some good type alias features
RRotor2/15/2023
Alright gave this one a go and I think it's a small enough crime that I'll risk the Unsafe cast and make sure it's covered properly with tests. Thanks very much for the solution