Class AwaitableResult
- Namespace
- Dynamitey
- Assembly
- Dynamitey.Community.dll
Wraps a Task - specifically a Task<TResult> or a
ValueTask<TResult> whose TResult is not accessible to the calling
assembly - so that await, including a dynamically-bound await on the
dynamic result of InvokeMember(object, String_OR_InvokeMemberName, params object?[]), can complete without
the C# runtime binder ever needing to know TResult.
public sealed class AwaitableResult
- Inheritance
-
AwaitableResult
- Inherited Members
Remarks
await on a dynamic expression compiles to dynamic invocations of
GetAwaiter, IsCompleted and GetResult, resolved by the C# runtime binder in the
CALLING assembly's accessibility context. When the awaited Task<TResult>'s
TResult is not visible to the caller, the binder cannot produce a value of that type,
GetResult binds to a void-returning form instead, and the compiler-generated conversion of
the await expression's result throws
RuntimeBinderException ("Cannot implicitly convert
type 'void' to 'object'").
This wrapper sidesteps that failure: every member the await pattern needs -
GetAwaiter(), IsCompleted, GetResult() - is a
public member with a public signature. GetResult() in particular is declared to
return object, never TResult, so the runtime binder can resolve it regardless
of whether the caller can see TResult. Internally, the wrapper observes the underlying task
through its statically-typed, non-generic Task base (so no binder or generic
instantiation ever touches TResult) and then reads the result value out via reflection, which
is not subject to accessibility checks. The caller still gets the real result instance back - just
boxed as object instead of typed as TResult.
InvokeMember(object, String_OR_InvokeMemberName, params object?[]) returns this wrapper when the invoked member's result is a
Task<TResult> or a ValueTask<TResult> whose TResult is not
visible outside its declaring assembly (see IsVisible, which - unlike
IsPublic - correctly treats a public type nested inside another public type
as visible). An inaccessible ValueTask<TResult> is converted with AsTask()
first so this wrapper stays Task-based. Every other result - a plain Task, or a
Task<TResult> / ValueTask<TResult> whose TResult is visible
to callers - passes through unwrapped and behaves exactly as before.
Constructors
AwaitableResult(Task)
Wraps task for accessibility-safe awaiting.
public AwaitableResult(Task task)
Parameters
taskTaskThe task to wrap.
Exceptions
- ArgumentNullException
taskis null.
Properties
Task
The underlying task this wrapper awaits. Use this when you need the real Task itself - e.g. to pass it to AwaitResult(object?), inspect IsFaulted, or hand it to other task-based code.
public Task Task { get; }
Property Value
Methods
GetAwaiter()
Returns the awaiter used by await. Not meant to be called directly - the compiler (or,
for a dynamically-typed await, the C# runtime binder) calls this as part of the await
pattern.
public AwaitableResult.Awaiter GetAwaiter()