using System.Collections.Generic;
using System.Threading.Tasks;
public static void Main(string[] args)
var task = ProcessExpandedAsync(new FileInfo[]{
Console.WriteLine("Results:");
foreach (var item in task.Result)
string txt = string.Join(", ", item.Dependencies);
Console.WriteLine("{0}: ({1})", item.FilePath, txt);
Console.WriteLine("Done.");
public static async Task<ICollection<FileData>> ProcessAsync(IEnumerable<FileInfo> files)
var map = new Dictionary<FileInfo, Task<FileData>>();
var tasks = files.Select(it => LoadFileDataAsync(it, map));
return await Task.WhenAll(tasks).ConfigureAwait(false);
public static async Task<ICollection<FileData>> ProcessExpandedAsync(IEnumerable<FileInfo> files)
var map = new Dictionary<FileInfo, Task<FileData>>();
var tasks = files.Select(it => (Task)LoadFileDataAsync(it, map));
await Task.WhenAll(tasks).ConfigureAwait(false);
return map.Values.Select(it=>it.Result).ToArray();
static async Task<FileData> LoadFileDataAsync(FileInfo fileInfo, Dictionary<FileInfo, Task<FileData>> map)
Task<FileData> pendingTask;
isNew = !map.TryGetValue(fileInfo, out pendingTask);
pendingTask = FileData.CreateAsync(fileInfo);
map.Add(fileInfo, pendingTask);
if (!isNew && !pendingTask.IsCompleted)
Console.WriteLine("{0}:Waiting on {1}", System.Threading.Thread.CurrentThread.ManagedThreadId, fileInfo.Path);
var data = await pendingTask.ConfigureAwait(false);
data.Dependencies = ExpandDependencies(data.DependsUpon, map);
if (data.DependsUpon.Count > 0)
var tasks = data.DependsUpon.Select(it => (Task)LoadFileDataAsync(it, map));
await Task.WhenAll(tasks).ConfigureAwait(false);
static IEnumerable<FileInfo> ExpandDependencies(ISet<FileInfo> directDependencies, Dictionary<FileInfo, Task<FileData>> map)
if (directDependencies.Count == 0)
var visited = new HashSet<FileInfo>(map.Comparer);
var stack = new Stack<FileInfo>();
foreach (var item in directDependencies)
var data = map[info].Result;
foreach (var child in data.DependsUpon)
public class FileInfo : IEquatable<FileInfo>
public FileInfo(string path)
public bool Equals(FileInfo other)
return StringComparer.OrdinalIgnoreCase.Equals(this.Path, other.Path);
public override string ToString()
public override int GetHashCode()
return StringComparer.OrdinalIgnoreCase.GetHashCode(Path);
public string FilePath { get; set; }
public ISet<FileInfo> DependsUpon { get; set; }
public IEnumerable<FileInfo> Dependencies { get; set; }
public static async Task<FileData> CreateAsync(FileInfo fileInfo)
Console.WriteLine("{0}:Start {1}", System.Threading.Thread.CurrentThread.ManagedThreadId, fileInfo.Path);
int waitTimeMs = rnd.Next(100, 1000);
await Task.Delay(waitTimeMs).ConfigureAwait(false);
FileData data = new FileData();
data.FilePath = fileInfo.Path;
data.DependsUpon = new HashSet<FileInfo>(TestData.Get(fileInfo.Path));
Console.WriteLine("{0}:Completed {1}", System.Threading.Thread.CurrentThread.ManagedThreadId, fileInfo.Path);
static Random rnd = new Random();
public static FileInfo[] Get(string path)
if (_map.TryGetValue(path, out values))
return values.Select(it => new FileInfo(it)).ToArray();
_map = new Dictionary<string, string[]>();
_map["A"] = new string[] { "B", "F" };
_map["B"] = new string[] { "C", "D"};
_map["D"] = new string[] { "E" };
_map["F"] = new string[] { "C" };
_map["G"] = new string[] { "H", "D", "J"};
_map["H"] = new string[] { "I" };
static Dictionary<string, string[]> _map;