Can I await something if there's no GetAwaiter method?
Asked Answered
A

2

8

I saw some articles about designing a custom awaitable type:

http://books.google.com.br/books?id=1On1glEbTfIC&pg=PA83&lpg=PA83&dq=create+a+custom+awaitable+type

Now consider the example below:

<Button x:Name="BtnA"
        Width="75"
        Margin="171,128,0,0"
        HorizontalAlignment="Left"
        VerticalAlignment="Top"
        Click="BtnA_Click"
        Content="Button A" />
<Button x:Name="BtnB"
        Width="75"
        Margin="273,128,0,0"
        HorizontalAlignment="Left"
        VerticalAlignment="Top"
        Content="Button B"  Click="BtnB_OnClick" />

and:

private async void BtnA_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show("Awaiting Button B..");

    var sx = Observable.FromEvent<MouseButtonEventHandler, 
                                  MouseButtonEventArgs>(a => (b, c) => a(c),
                                  add => BtnB.PreviewMouseDown += add,
                                  rem => BtnB.PreviewMouseDown -= rem)
       .Do(a => a.Handled = true)
       .Take(1);

    await sx;

    MessageBox.Show("Button B Pressed after Button A");
}

private void BtnB_OnClick(object sender, RoutedEventArgs e)
{
    MessageBox.Show("Button B Pressed Without Click in Button A");
}

Why can I await IObservable<T> (in this case when subscription is completed), if there's no GetAwaiter() method?

Is it implemented by the compiler? Is it possible to implement something that can await without to explicit this method (some scenarios which interfaces is being used)? And why isn't there something like:

public interface ITask<out T>
{
    IAwaiter<T> GetAwaiter();
}

public interface IAwaiter<out T> : ICriticalNotifyCompletion
{
    bool IsCompleted { get; }
    T GetResult();
}

... or real interfaces to create a custom awaitable?

Aultman answered 25/9, 2014 at 19:41 Comment(2)
If you're reading a book on the subject what does it say on the matter? Does it not explain its own example?Marla
Forget it, I missed the part of "That GetAwait method can be an extension method.."Aultman
P
22

First of all, no.

You can't await something that doesn't have a GetAwaiter method that returns something that has GetResult, OnCompleted, IsCompleted and implements INotifyCompletion.

So, how are you able to await an IObservable<T>?

The compiler, on top of instance methods, also accepts GetAwaiter extensions methods. In this case Reactive Extensions's Observable provides that extension:

public static AsyncSubject<TSource> GetAwaiter<TSource>(this IObservable<TSource> source);

For example, this is how we can make strings awaitable (which compiles but obviously won't actually work):

public static Awaiter GetAwaiter(this string s)
{
    throw new NotImplementedException();
}
public abstract class Awaiter : INotifyCompletion
{
    public abstract bool IsCompleted { get; }
    public abstract void GetResult();
    public abstract void OnCompleted(Action continuation);
}

await "bar";
Perforce answered 25/9, 2014 at 19:54 Comment(0)
G
2

You can supply your own implementation of GetAwaiter via an extension method if one does not exist.

http://blogs.msdn.com/b/pfxteam/archive/2011/01/13/10115642.aspx

Glimpse answered 26/9, 2014 at 20:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.