interface IMyAsyncInterface
{
    Task<int> CountBytesAsync(string url);
}

class MyAsyncClass : IMyAsyncInterface
{
    public async Task<int> CountBytesAsync(string url)
    {
        var client = new HttpClient();
        var bytes = await client.GetByteArrayAsync(url);
        return bytes.Length;
    }
}

static async Task UseMyInterfaceAsync(IMyAsyncInterface service)
{
    var result = await service.CountBytesAsync("http://www.example.com");
    Trace.WriteLine(result);
}

---

class MyAsyncClassStub : IMyAsyncInterface
{
    public Task<int> CountBytesAsync(string url)
    {
        return Task.FromResult(13);
    }
}

---

var instance = new MyAsyncClass();
await instance.InitializeAsync();

---

class MyAsyncClass
{
    private MyAsyncClass()
    {
    }

    private async Task<MyAsyncClass> InitializeAsync()
    {
        await Task.Delay(TimeSpan.FromSeconds(1));
        return this;
    }

    public static Task<MyAsyncClass> CreateAsync()
    {
        var result = new MyAsyncClass();
        return result.InitializeAsync();
    }
}

---

var instance = await MyAsyncClass.CreateAsync();

---

class MyAsyncClass
{
    public MyAsyncClass()
    {
        InitializeAsync();
    }

    // ZŁY KOD!!!
    private async void InitializeAsync()
    {
        await Task.Delay(TimeSpan.FromSeconds(1));
    }
}

---

Task Initialization { get; }

---

/// <summary>
/// Oznacza typ jako wymagający inicjowania asynchronicznego
/// i zapewnia wynik tego inicjowania.
/// </summary>
public interface IAsyncInitialization
{
    /// <summary>
    /// Wynik inicjowania asynchronicznego tej instancji.
    /// </summary>
Task Initialization { get; }
}

---

class MyFundamentalType : IMyFundamentalType, IAsyncInitialization
{
    public MyFundamentalType()
    {
        Initialization = InitializeAsync();
    }

    public Task Initialization { get; private set; }

    private async Task InitializeAsync()
    {
        // Asynchroniczne inicjowanie tej instancji.
        await Task.Delay(TimeSpan.FromSeconds(1));
    }
}

---

IMyFundamentalType instance = UltimateDIFactory.Create<IMyFundamentalType>();
var instanceAsyncInit = instance as IAsyncInitialization;
if (instanceAsyncInit != null)
    await instanceAsyncInit.Initialization;

---

class MyComposedType : IMyComposedType, IAsyncInitialization
{
    private readonly IMyFundamentalType _fundamental;

    public MyComposedType(IMyFundamentalType fundamental)
    {
        _fundamental = fundamental;
        Initialization = InitializeAsync();
    }

    public Task Initialization { get; private set; }

    private async Task InitializeAsync()
    {
        // W razie potrzeby asynchroniczne zainicjowanie instancji fundamental.
        var fundamentalAsyncInit = _fundamental as IAsyncInitialization;
        if (fundamentalAsyncInit != null)
            await fundamentalAsyncInit.Initialization;

        // Wykonanie własnego inicjowania (synchronicznego lub asynchronicznego).
        ...
    }
}

---

public static class AsyncInitialization
{
    static Task WhenAllInitializedAsync(params object[] instances)
    {
        return Task.WhenAll(instances
            .OfType<IAsyncInitialization>()
            .Select(x => x.Initialization));
    }
}

---

private async Task InitializeAsync()
{
    // W razie potrzeby asynchroniczne oczekiwanie na zainicjowanie wszystkich trzech instancji.
    await AsyncInitialization. WhenAllInitializedAsync(_fundamental,
        _anotherType, _yetAnother);

    // Wykonanie własnego inicjowania (synchronicznego lub asynchronicznego).
    ...
}

---

public int Data
{
    async get
    {
        await Task.Delay(TimeSpan.FromSeconds(1));
        return 13;
    }
}

---

public async Task<int> GetDataAsync()
{
    await Task.Delay(TimeSpan.FromSeconds(1));
    return 13;
}

---

public Task<int> Data
{
    get { return GetDataAsync(); }
}

private async Task<int> GetDataAsync()
{
    await Task.Delay(TimeSpan.FromSeconds(1));
    return 13;
}

---

public AsyncLazy<int> Data
{
    get { return _data; }
}

private readonly AsyncLazy<int> _data =
    new AsyncLazy<int>(async () =>
    {
        await Task.Delay(TimeSpan.FromSeconds(1));
        return 13;
    });

---

int value = await instance.Data;

---

private async Task<int> GetDataAsync()
{
    await Task.Delay(TimeSpan.FromSeconds(1));
    return 13;
}

public int Data
{
    // ZŁY KOD!!!
    get { return GetDataAsync().Result; }
}

---

public class MyEventArgs : EventArgs
{
    private readonly DeferralManager _deferrals = new DeferralManager();

    ... // Twoje własne konstruktory i właściwości.

    public IDisposable GetDeferral()
    {
        return _deferrals.GetDeferral();
    }

    internal Task WaitForDeferralsAsync()
    {
        return _deferrals.SignalAndWaitAsync();
    }
}

---

public event EventHandler<MyEventArgs> MyEvent;

private Task RaiseMyEventAsync()
{
    var handler = MyEvent;
    if (handler == null)
        return Task.FromResult(0);

    var args = new MyEventArgs(...);
    handler(this, args);
    return args.WaitForDeferralsAsync();
}

---

async void AsyncHandler(object sender, MyEventArgs args)
{
    using (args.GetDeferral())
    {
        await Task.Delay(TimeSpan.FromSeconds(2));
    }
}

---

class MyClass : IDisposable
{
    private readonly CancellationTokenSource _disposeCts =
        new CancellationTokenSource();

    public async Task<int> CalculateValueAsync()
    {
        await Task.Delay(TimeSpan.FromSeconds(2), _disposeCts.Token);
        return 13;
    }

    public void Dispose()
    {
        _disposeCts.Cancel();
    }
}

---

public async Task<int> CalculateValueAsync(CancellationToken cancellationToken)
{
    using (var combinedCts = CancellationTokenSource
        .CreateLinkedTokenSource(cancellationToken, _disposeCts.Token))
    {
        await Task.Delay(TimeSpan.FromSeconds(2), combinedCts.Token);
        return 13;
    }
}

---

async Task Test()
{
    Task<int> task;
    using (var resource = new MyClass())
    {
        task = CalculateValueAsync();
    }

    // Rzuca wyjątek OperationCanceledException.
    var result = await task;
}

---

/// <summary>
/// Oznacza typ jako wymagający zakończenia asynchronicznego
/// i zapewnia wynik tego zakończenia.
/// </summary>
interface IAsyncCompletion
{
    /// <summary>
    /// Rozpoczyna zakończenie tej instancji. Koncepcyjnie jest to podobne
    /// do <see cref="IDisposable.Dispose"/>.
    /// Po wywołaniu tej metody nie należy wywoływać żadnej innej składowej
    /// tej instancji z wyjątkiem <see cref="Completion"/>.
    /// </summary>
    void Complete();
    /// <summary>
    /// Pobiera wynik zakończenia tej instancji.
    /// </summary>
    Task Completion { get; }
}

---

class MyClass : IAsyncCompletion
{
    private readonly TaskCompletionSource<object> _completion =
        new TaskCompletionSource<object>();
    private Task _completing;

    public Task Completion
    {
        get { return _completion.Task; }
    }

    public void Complete()
    {
        if (_completing != null)
            return;
       _completing = CompleteAsync();
    }

    private async Task CompleteAsync()
    {
        try
        {
            ... // Asynchroniczne oczekiwanie na istniejące operacje.
        }
        catch (Exception ex)
        {
            _completion.TrySetException(ex);
        }
        finally
        {
            _completion.TrySetResult(null);
        }
    }
}

---

static class AsyncHelpers
{
    public static async Task Using<TResource>(Func<TResource> construct,
        Func<TResource, Task> process) where TResource : IAsyncCompletion
    {
        // Tworzenie zasobu, którego używamy.
        var resource = construct();

        // Użycie zasobu przy wyłapywaniu wszelkich wyjątków.
        Exception exception = null;
        try
        {
            await process(resource);
        }
        catch (Exception ex)
        {
            exception = ex;
        }

        // Zakończenie (logicznie usunięcie) zasobu.
        resource.Complete();
        await resource.Completion;

        // W razie potrzeby ponowne rzucenie wyjątku delegata procesu.
        if (exception != null)
            ExceptionDispatchInfo.Capture(exception).Throw();
    }

    public static async Task<TResult> Using<TResource, TResult>(
        Func<TResource> construct, Func<TResource,
        Task<TResult>> process) where TResource : IAsyncCompletion
    {
        // Utworzenie zasobu, którego używamy.
        var resource = construct();

        // Użycie zasobu przy wyłapywaniu wszelkich wyjątków.
        Exception exception = null;
        TResult result = default(TResult);
        try
        {
            result = await process(resource);
        }
        catch (Exception ex)
        {
            exception = ex;
        }

        // Zakończenie (logicznie usunięcie) zasobu.
        resource.Complete();
        try
        {
            await resource.Completion;
        }
        catch
        {
            // Dopuszczenie wyjątków z Completion tylko wtedy,
            // jeśli delegat procesu nie rzucił wyjątku.
            if (exception == null)
                throw;
        }
 
        // W razie potrzeby ponowne rzucenie wyjątku delegata procesu.
        if (exception != null)
            ExceptionDispatchInfo.Capture(exception).Throw();

        return result;
    }
}

---

async Task Test()
{
    await AsyncHelpers.Using(() => new MyClass(), async resource =>
    {
        // Użycie zasobu.
    });
}
