Closed KevinRansom closed 5 years ago
There is a difference when cast as a generic IEnumerable
vs non-generic IEnumerable
.
If you change the interface cast to System.Collections.IEnumerable
(non-generic), it behaves as you'd expect:
open System
open System.Collections
open System.Collections.Generic
[<EntryPoint>]
let main argv =
let ie = (dict [|(1,1);(2,4);(3,9)|]) :> IEnumerable//<KeyValuePair<_,_>>
let enum = ie.GetEnumerator()
let step2 = enum.MoveNext()
let step3 = enum.Current
printfn "%b %A" step2 step3 |> ignore
let step4 = enum.MoveNext()
let step5 = enum.Current
printfn "%b %A" step4 step5 |> ignore
let step6 = enum.MoveNext()
let step7 = enum.Current
printfn "%b %A" step6 step7 |> ignore
let step8 = enum.MoveNext()
let step9 = enum.Current
printfn "%b %A" step8 step9 |> ignore
let step10 = enum.MoveNext()
let step11 = enum.Current
printfn "%b %A" step10 step11 |> ignore
Somehow, using seq<_>
is what causes the difference on .NET Core.
@cartermp yes, it is indeed the generic that is broken.
This is a coreclr bug, issued raised with them here: https://github.com/dotnet/core/issues/2064
Here is the C# repro, if you are interested:
namespace ConsoleApp23
{
class Program
{
static void Main(string[] args)
{
var keyValuePairs =
new KeyValuePair<int, int>[3]
{
new KeyValuePair<int, int>(1,1),
new KeyValuePair<int, int>(2,2),
new KeyValuePair<int, int>(3,3),
};
IEnumerable<KeyValuePair<int, int>> collection = keyValuePairs;
var e = collection.GetEnumerator();
var step2 = e.MoveNext();
var step3 = e.Current;
Console.WriteLine("{0} {1}", step2, step3);
var step4 = e.MoveNext();
var step5 = e.Current;
Console.WriteLine("{0} {1}", step4, step5);
var step6 = e.MoveNext();
var step7 = e.Current;
Console.WriteLine("{0} {1}", step6, step7);
var step8 = e.MoveNext();
var step9 = e.Current;
Console.WriteLine("{0} {1}", step8, step9);
}
}
}
Closing. Thanks for investigating, didn't expect it to be a .NET Core bug!
So, I think I am going to provide a fix in FSharp.Core.
This code behaves differently on NetCore and NetFramework
What happens is when MoveNext has moved past the end of the collection it's Enumerator needs to throw invalid operation exception on Current, instead it grabs the last value