Out of curiosity, I'm trying to get some simple async
/await
code to compile under .NET 3.5 Client Profile:
async void AwaitFoo()
{
await new Foo();
}
class Foo
{
public IFooAwaiter GetAwaiter() { … }
}
interface IFooAwaiter : System.Runtime.CompilerServices.INotifyCompletion
{
bool IsCompleted { get; }
void GetResult();
}
I'm perfectly aware that .NET 3.5 does not support this language feature, as expressed by this compilation error:
Cannot find all types required by the
async
modifier. Are you targeting the wrong framework version, or missing a reference to an assembly?
I am also aware of the NuGet package Microsoft.Bcl.Async
, which does not have support for .NET 3.5.
Question: What is the minimum set of types & type members required for async
code to compile? Is this minimal set officially documented; and if so, where? (Note that I'm only interested in successful compilation, not execution.)
What I've got so far:
I've been trying to find this minimum set of types by experiment, which appears to be possible since the compiler reports required, but missing types one by one:
Predefined type
System.Runtime.CompilerServices.IAsyncStateMachine
is not defined or imported.
Defining the reported type according to MSDN reference pages then leads to the next missing type being reported. I have so far:
System.Runtime.CompilerServices.IAsyncStateMachine
System.Runtime.CompilerServices.INotifyCompletion
(required by the example code above)System.Threading.Tasks.CancellationToken
(required by Task
)System.Threading.Tasks.TaskCreationOptions
(required by Task
)System.Threading.Tasks.Task
At this point I stopped, since Task
has lots of members, but the compiler does not report exactly which members it requires; it just reports the type as a whole. I might therefore reproduce much more of the type definition than what is actually needed.
In terms of the C# compiler, you also need:
AsyncTaskMethodBuilder
AsyncTaskMethodBuilder<TResult>
AsyncVoidMethodBuilder
AsyncStateMachineAttribute
ICriticalNotifyCompletion
although I believe that' just used by the builder.I wouldn't expect that either TaskCreationOptions
or CancellationToken
would actually be required - I can't think where they'd be used in the generated code.
Fundamentally though, you really need the whole TPL support for it to work - just having it compile isn't going do it for you. If you're only interested in this for curiosity, that's a different matter. You might be interested in my Eduasync blog series, which was a crude version of getting the CTP release of the compiler to work without the AsyncCtpLibrary.dll
assembly (against .NET 4.0) - basically supplying all the relevant types.
The source code won't work against the C# 5 compiler as things changed a bit for the final release, but most of the concepts have stayed the same.
I've determined by experiment that the following types are sufficient in order to make the C# 5 compiler process basic async
/await
code (even when targeting .NET Framework version 2!):
IAsyncStateMachine
INotifyCompletion
(no member declarations needed)ICriticalNotifyCompletion
(no member declarations needed)AsyncVoidMethodBuilder
AsyncTaskMethodBuilder
AsyncTaskMethodBuilder<TResult>
Task
(no member declarations needed)Task<TResult>
(no member declarations needed)The most minimal declarations for these that I've found to be acceptable to the C# compiler follow below.
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 { … } }
}
}
(I am throwing a NotImplementedException
wherever it says { … }
.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With