2015-01-30 8 views
5

Sto guardando Task.Delay(int) decompilato in ILSpy:In che modo Task.Delay è attendibile se non è contrassegnato come asincrono?

// System.Threading.Tasks.Task 
[__DynamicallyInvokable] 
public static Task Delay(int millisecondsDelay) 
{ 
    return Task.Delay(millisecondsDelay, default(CancellationToken)); 
} 

Questo metodo viene utilizzato come await Task.Delay(5000);, e l'intellisense dice addirittura "(awaitable)":

enter image description here

Così come è possibile che Task.Delay(int) non è contrassegnato con async (public static async Task Delay(int millisecondsDelay))?

+3

Sono compiti che sono attesi, non le funzioni che li restituiscono. – Lee

+3

[Domande frequenti su Async/Await] (http://blogs.msdn.com/b/pfxteam/archive/2012/04/12/10293335.aspx): "Un" attendibile "è un tipo che espone un metodo GetAwaiter che restituisce un "cameriere" valido. Questo metodo GetAwaiter può essere un metodo di istanza (come nel caso di Task e Task ), oppure può essere un metodo di estensione. " –

+0

@ I3arnon - È stato modificato per aggiungere il tag C#, ma questa non è specificamente una domanda C# (è solo la lingua mostrata da ILSpy). Potrei usare 'Task.Delay' da VB.NET. –

risposta

17

Ciò che è attendibile sono i ritorni TaskTask.Delay. Ogni metodo che restituisce un Task/Task<TResult> è attendibile. async è solo un dettaglio di implementazione che consente di utilizzare await in tale metodo e l'intera macchina a stati che genera.

Più in generale, ogni cosa che ha un metodo GetAwaiter (extension methods count as well) che restituiscono qualcosa che ha IsCompleted, OnCompleted e GetResult può essere atteso.

Per esempio, Task.Yield rendimenti YieldAwaitable che non è una Task e si presenta così:

public struct YieldAwaiter : ICriticalNotifyCompletion, INotifyCompletion 
{ 
    public void OnCompleted(Action continuation); 
    public void UnsafeOnCompleted(Action continuation); 
    public void GetResult(); 
    public bool IsCompleted { get; } 
} 

* UnsafeOnCompleted qui è solo un'ottimizzazione, await avrebbe funzionato senza di essa.

È importante notare che il compilatore in questo caso (come in altri casi come GetEnumerator per foreach) non prevede un'interfaccia o una classe base. In pratica utilizza duck typing (ovvero "se cammina come un'anatra ...") e cerca semplicemente un metodo GetAwaiter che restituisce qualcosa (non importa quale tipo o interfaccia o se è una classe o una struttura) che ha gli altri 3 membri (IsCompleted, OnCompleted e GetResult)

Ad esempio, questo è come si può fare await "bar" compilazione (fallirà nel runtime ovviamente):

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); 
} 

in conclusione, non è necessario necessario async per restituire un aspetto attendibile e inoltre più Task - metodi di restituzione nel framework .Net non lo usano e restituiscono esplicitamente un Task.

+0

Bello. Quindi, senza guardarci ancora - esiste un'interfaccia che Task o qualsiasi altra cosa implementa che abbia un metodo 'GetAwaiter' e abbia' IsCompleted', 'OnCompleted' e' GetResult'? In altre parole, come viene raggiunto? –

+0

Non dovrebbe lo strumento attendibile 'INotifyCompletion' o' ICriticalNotifyCompletion'? –

+0

@roryap - Guarda in 'INotifyCompletion' –

Problemi correlati