You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This API was proposed before and already rejected.
But why it could not be implemented like this:
publicstaticexplicitoperator ValueTask(ValueTask<TResult>task){if(valueTask.IsCompletedSuccessfully){valueTask.GetAwaiter().GetResult();returndefault;}if(task._objis not IValueTaskSourcevts)returnnewValueTask(task.AsTask());returnnewValueTask(vts,task._token,task._continueOnCapturedContext);}
It may be useful because:
this conversion already exists for Task<T>/Task, and adding this to ValueTask improves user experience when moving to ValueTask/ValueTask<T>
most runtime types implementing IValueTaskSource<T> also implements the non-generic IValueTaskSource: AsyncOperation<TResult>, PoolingAsyncValueTaskMethodBuilder<T>.StateMachineBox, AwaitableSocketAsyncEventArgs , PipeStream.PipeValueTaskSource, ManualResetValueTaskSource, so it is not useless method which will always fall back to the .AsTask() call with allocation.
If the only concerns are things like awaiting twice, or different .GetResult(token) implementations, this conversion may be added as hard to access method, like ref-returning methods in the CollectionsMarshal class.
We don't know for certain that the IValueTaskSource implementation is identical in purpose to the IValueTaskSource<T> implementation. Lots of implementations try to avoid allocation by implementing multiple interfaces for different purposes on the same object. You can, for example, implement IValueTaskSource<long> on an object to support a CountResultsAsync and an IValueTaskSource<double> on that same object to support a different ComputePiAsync, and so we can't assume that for example the OnCompleted they both share serves the same purpose. Similarly, assuming that an IValueTaskSource's implementation is substitutable for an IValueTaskSource<T>'s implementation could lead to bugs. We can do so for our own objects where we know they have the same behavior ("runtime already uses this conversion inside), but doing so generally isn't guaranteed.
Thank you for an answer! I got it that in many cases a simple cast won't work.
But it is still looks solvable by introducing some proxy on top of IValueTaskSource<TResult>. Unfortunately, this wrapper couldn't be implemented safely in user code, as it requires access to the underlying ValueTask<TResult>._obj field.
internalclassValueTaskSourceProxy<TResult>:IValueTaskSource{privateIValueTaskSource<TResult>source;privateValueTaskSourceProxy(){}publicstaticValueTaskSourceProxy<TResult>For(IValueTaskSource<TResult>source){// proxy objects are pooled like PoolingAsyncValueTaskMethodBuilder<TResult>.StateMachineBox<TStateMachine>varproxy=pool.TryRent()??new();proxy.source=source;returnproxy;}publicvoidGetResult(shorttoken){try{source.GetResult(token);}finally{source=default;pool.Return(this);}}publicValueTaskSourceStatusGetStatus(shorttoken)=>source.GetStatus(token);publicvoidOnCompleted(Action<object?>continuation,object?state,shorttoken,ValueTaskSourceOnCompletedFlagsflags)=>source.OnCompleted(continuation,state,token,flags);}publicstaticexplicitoperator ValueTask(ValueTask<TResult>task){if(valueTask.IsCompletedSuccessfully){valueTask.GetAwaiter().GetResult();returndefault;}if(task._objis not IValueTaskSource<TResult>vts)returnnewValueTask(task.AsTask());returnnewValueTask(ValueTaskSourceProxy<TResult>.For(vts),task._token,task._continueOnCapturedContext);}
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
This API was proposed before and already rejected.
But why it could not be implemented like this:
It may be useful because:
Task<T>/Task
, and adding this toValueTask
improves user experience when moving toValueTask/ValueTask<T>
IValueTaskSource<T>
also implements the non-genericIValueTaskSource
:AsyncOperation<TResult>
,PoolingAsyncValueTaskMethodBuilder<T>.StateMachineBox
,AwaitableSocketAsyncEventArgs
,PipeStream.PipeValueTaskSource
,ManualResetValueTaskSource
, so it is not useless method which will always fall back to the.AsTask()
call with allocation.If the only concerns are things like awaiting twice, or different
.GetResult(token)
implementations, this conversion may be added as hard to access method, like ref-returning methods in theCollectionsMarshal
class.Beta Was this translation helpful? Give feedback.
All reactions