I am experiencing a strange issue while enumerating an IAsyncEnumerable
, with the System.Linq.Async operator Take
attached to it. In my iterator I have a try-finally block with some values yielded inside the try
block, and some clean-up code inside the finally
block. The clean-up code is inside a lock
block. The issue is that whatever code follows the lock
block is not executed. No exception is thrown, the code is just ignored like it's not there. Here is a program that reproduces this behavior:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
public class Program
{
static async Task Main()
{
await foreach (var item in GetStream().Take(1))
{
Console.WriteLine($"Received: {item}");
}
Console.WriteLine($"Done");
}
static async IAsyncEnumerable<int> GetStream()
{
var locker = new object();
await Task.Delay(100);
try
{
yield return 1;
yield return 2;
}
finally
{
Console.WriteLine($"Finally before lock");
lock (locker) { /* Clean up */ }
Console.WriteLine($"Finally after lock");
}
}
}
Output:
Received: 1
Finally before lock
Done
The text "Finally after lock" is not printed in the console!
This only happens with the Take
operator attached. Without the operator the text is printed as expected.
Is this a bug in the System.Linq.Async
library, a bug in the C# compiler, or something else?
As a workaround I am currently using a nested try-finally block inside the finally
, which works but it's awkward:
finally
{
try
{
lock (locker) { /* Clean up */ }
}
finally
{
Console.WriteLine($"Finally after lock");
}
}
.NET Core 3.1.3, .NET Framework 4.8.4150.0, C# 8, System.Linq.Async 4.1.1, Visual Studio 16.5.4, Console Application