I would like to generate an observable of files, such that the discovery of the files names could be cancelled in any moment. For the sake of this example, the cancellation takes place in 1 second automatically.
Here is my current code:
class Program
{
static void Main()
{
try
{
RunAsync(@"\\abc\xyz").GetAwaiter().GetResult();
}
catch (Exception exc)
{
Console.Error.WriteLine(exc);
}
Console.Write("Press Enter to exit");
Console.ReadLine();
}
private static async Task RunAsync(string path)
{
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
await GetFileSource(path, cts);
}
private static IObservable<string> GetFileSource(string path, CancellationTokenSource cts)
{
return Observable.Create<string>(obs => Task.Run(async () =>
{
Console.WriteLine("Inside Before");
foreach (var file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories).Take(50))
{
cts.Token.ThrowIfCancellationRequested();
obs.OnNext(file);
await Task.Delay(100);
}
Console.WriteLine("Inside After");
obs.OnCompleted();
return Disposable.Empty;
}, cts.Token))
.Do(Console.WriteLine);
}
}
I do not like two aspects of my implementation (if there are more - please feel free to point out):
- I have an enumerable of files, yet I iterate over each manually. Could I use the
ToObservable
extension somehow? - I could not figure out how to make use of the
cts.Token
passed toTask.Run
. Had to use thects
captured from the outer context (GetFileSource
parameter). Seems ugly to me.
Is this how it should be done? Must be a better way.