2013-07-31 28 views
6

Z ciekawości, staram się trochę prosty kod async/await skompilować pod .NET 3.5 Client Profile:Jaki jest minimalny zestaw typów wymaganych do kompilacji kodu `asynchronicznego`?

async void AwaitFoo() 
{ 
    await new Foo(); 
} 

class Foo 
{ 
    public IFooAwaiter GetAwaiter() { … } 
} 

interface IFooAwaiter : System.Runtime.CompilerServices.INotifyCompletion 
{ 
    bool IsCompleted { get; } 
    void GetResult(); 
} 

jestem doskonale świadomy, że .NET 3.5 nie obsługuje tej funkcji języka, wyrażone przez ten błąd kompilacji:

Cannot find all types required by the async modifier. Are you targeting the wrong framework version, or missing a reference to an assembly?

Jestem też świadomy NuGet package Microsoft.Bcl.Async, który nie posiada wsparcia dla .NET 3.5.

Pytanie: Jaki jest minimalny zestaw typów & członkowie typu wymagana async kodu skompilować? Czy ten minimalny zestaw został oficjalnie udokumentowany; a jeśli tak, to gdzie? (Zauważ, że jestem zainteresowany tylko udanej kompilacji, a nie wykonanie.)


co mam do tej pory:

Próbowałem znaleźć ten minimalny zestaw typów przez eksperyment, który wydaje się być możliwe, ponieważ raportów wymaganych kompilatora, ale brakuje rodzaje jeden po drugim:

Predefined type System.Runtime.CompilerServices.IAsyncStateMachine is not defined or imported.

Definiowanie zgłoszony typ według stron referencyjnych MSDN prowadzi następnie do następnego brakującym typu są zgłaszane. I tak daleko:

  • System.Runtime.CompilerServices.IAsyncStateMachine
  • System.Runtime.CompilerServices.INotifyCompletion (wymagane przez kod przykładu)
  • System.Threading.Tasks.CancellationToken (wymaganych Task)
  • System.Threading.Tasks.TaskCreationOptions (wymaganych Task)
  • System.Threading.Tasks.Task

W tym momencie s zwieńczone, ponieważ Task ma wielu członków, ale kompilator nie zgłasza dokładnie, których członków wymaga; po prostu zgłasza typ jako całość. Mogę zatem odtworzyć znacznie więcej definicji typu niż to, co jest rzeczywiście potrzebne.

Odpowiedz

2

mam określić doświadczalnie, że następujące typy są wystarczające w celu dokonania procesu kompilatora C# 5 podstawowych async/await kodu (nawet gdy ukierunkowanie .NET Framework w wersji 2!):

Najbardziej minimalne deklaracje dla nich, że znalazłem się być do zaakceptowania przez Kompilator C# wykonaj poniżej.

namespace System.Threading.Tasks 
{ 
    abstract class Task { } 
    abstract class Task<TResult> : Task { } 
} 

namespace System.Runtime.CompilerServices 
{ 
    interface INotifyCompletion { } 
    interface ICriticalNotifyCompletion { } 

    interface IAsyncStateMachine 
    { 
     void MoveNext(); 
     void SetStateMachine(IAsyncStateMachine stateMachine); 
    } 

    struct AsyncVoidMethodBuilder 
    { 
     public static AsyncVoidMethodBuilder Create() { … } 
     public void Start<TStateMachine>(ref TStateMachine stateMachine) 
      // where TStateMachine : IAsyncStateMachine 
      { … } 
     public void SetResult() { … } 
     public void SetException(Exception exception) { … } 
     public void SetStateMachine(IAsyncStateMachine stateMachine) { … } 
     public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) 
      // where TAwaiter : INotifyCompletion 
      // where TStateMachine : IAsyncStateMachine 
      { … } 
     public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) 
      // where TAwaiter : ICriticalNotifyCompletion 
      // where TStateMachine : IAsyncStateMachine 
      { … } 
    } 

    struct AsyncTaskMethodBuilder 
    { 
     public Task Task { get { … } } 
     public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) 
      // where TAwaiter : INotifyCompletion 
      // where TStateMachine : IAsyncStateMachine 
      { … } 
     public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) 
      // where TAwaiter : ICriticalNotifyCompletion 
      // where TStateMachine : IAsyncStateMachine 
      { … } 
     public static AsyncTaskMethodBuilder Create() { … } 
     public void SetException(Exception exception) { … } 
     public void SetResult() { … } 
     public void SetStateMachine(IAsyncStateMachine stateMachine) { … } 
     public void Start<TStateMachine>(ref TStateMachine stateMachine) 
      // where TStateMachine : IAsyncStateMachine 
      { … } 
    } 

    struct AsyncTaskMethodBuilder<TResult> 
    { 
     public static AsyncTaskMethodBuilder<TResult> Create() { … } 
     public void Start<TStateMachine>(ref TStateMachine stateMachine) 
      // where TStateMachine : IAsyncStateMachine 
      { … } 
     public void SetResult(TResult result) { … } 
     public void SetException(Exception exception) { … } 
     public void SetStateMachine(IAsyncStateMachine stateMachine) { … } 
     public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) 
      // where TAwaiter : INotifyCompletion 
      // where TStateMachine : IAsyncStateMachine 
      { … } 
     public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) 
      // where TAwaiter : ICriticalNotifyCompletion 
      // where TStateMachine : IAsyncStateMachine 
      { … } 
     public Task<TResult> Task { get { … } } 
    } 
} 

(ja rzucanie NotImplementedException gdziekolwiek mówi { … }.)

8

Pod względem kompilatora C#, trzeba również:

Nie oczekiwać że albo TaskCreationOptions lub CancellationToken byłby rzeczywiście wymagany - nie mogę myśleć, w których mają one być stosowane w wygenerowanego kodu.

Zasadniczo, naprawdę potrzebujesz pełnej obsługi TPL, aby działała - po prostu mając kompilować nie zrobi tego za Ciebie. Jeśli interesuje cię to tylko z ciekawości, to inna sprawa. Być może zainteresowałeś się moją serią blogów Eduasync, która była prymitywną wersją tworzenia wersji CTP kompilatora do pracy bez zestawu AsyncCtpLibrary.dll (w stosunku do .NET 4.0) - dostarczając praktycznie wszystkie odpowiednie typy.

Model source code nie będzie działał przeciwko kompilatorowi C# 5, ponieważ niektóre rzeczy zmieniły się nieco w ostatecznym wydaniu, ale większość koncepcji pozostała taka sama.

+0

Dzięki. Czy dowiedziałeś się o typach na twojej liście, czy też wziąłeś listę z oficjalnej dokumentacji? - Dziękuję również za link do Eduasync, już zacząłem czytać te artykuły na blogu. – stakx

+1

@stakx: Cóż, początkowo tworzyłem listę, kiedy się rozwijałem i zaimplementowałem fragmenty Eduasync - ale teraz patrzę na typy, które wiem, że kompilator używa w wygenerowanym kodzie. –