1) आप अपने EndExecute
विधि से अपवाद rethrow चाहिए।
2) मैं आपको अपना स्वयं का बेस प्रकार बनाने की सलाह देता हूं। मैं एक ऊपर से नीचे AsyncTaskCodeActivity<T>
बुलाया लिखा है:
public abstract class AsyncTaskCodeActivity<T> : AsyncCodeActivity<T>
{
protected sealed override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
var task = ExecuteAsync(context);
var tcs = new TaskCompletionSource<T>(state);
task.ContinueWith(t =>
{
if (t.IsFaulted)
tcs.TrySetException(t.Exception.InnerExceptions);
else if (t.IsCanceled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(t.Result);
if (callback != null)
callback(tcs.Task);
});
return tcs.Task;
}
protected sealed override T EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
var task = (Task<T>)result;
try
{
return task.Result;
}
catch (AggregateException ex)
{
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
throw;
}
}
protected abstract Task<T> ExecuteAsync(AsyncCodeActivityContext context);
}
तुम मेरे AsyncEx पुस्तकालय का उपयोग करते हैं, इस आवरण बहुत सरल हो जाता है:
public abstract class AsyncTaskCodeActivity<T> : AsyncCodeActivity<T>
{
protected sealed override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
var task = ExecuteAsync(context);
return AsyncFactory<T>.ToBegin(task, callback, state);
}
protected sealed override T EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
return AsyncFactory<T>.ToEnd(result);
}
protected abstract Task<T> ExecuteAsync(AsyncCodeActivityContext context);
}
एक बार जब आप आधार प्रकार है, आप अपने खुद के व्युत्पन्न प्रकार परिभाषित कर सकते हैं। यहाँ एक का उपयोग करता है है async
/await
:
public sealed class MyActivity : AsyncTaskCodeActivity<int>
{
protected override async Task<int> ExecuteAsync(AsyncCodeActivityContext context)
{
await Task.Delay(100);
return 13;
}
}
और यहाँ एक है कि कार्यक्रम थ्रेड पूल के लिए CPU बाध्य काम (अपने वर्तमान टेम्पलेट के समान) है:
public sealed class MyCpuActivity : AsyncTaskCodeActivity<int>
{
protected override Task<int> ExecuteAsync(AsyncCodeActivityContext context)
{
return Task.Run(() => 13);
}
}
टिप्पणियों से अद्यतन : यहां रद्दीकरण का उपयोग करने वाला एक है। मुझे 100% यकीन नहीं है कि यह सही है, क्योंकि रद्दीकरण स्वयं ही समकालिक है, और AsyncCodeActivity<T>.Cancel
के लिए अर्थशास्त्र दस्तावेज हैं (यानी, Cancel
को रद्द किए गए राज्य में गतिविधि को पूरा करने की प्रतीक्षा करनी चाहिए? क्या यह सफलतापूर्वक पूर्ण करने के लिए एक गतिविधि के लिए स्वीकार्य है Cancel
के बाद कहा जाता है?)।
public abstract class AsyncTaskCodeActivity<T> : AsyncCodeActivity<T>
{
protected sealed override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
var cts = new CancellationTokenSource();
context.UserState = cts;
var task = ExecuteAsync(context, cts.Token);
return AsyncFactory<T>.ToBegin(task, callback, state);
}
protected sealed override T EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
try
{
return AsyncFactory<T>.ToEnd(result);
}
catch (OperationCanceledException)
{
if (context.IsCancellationRequested)
context.MarkCanceled();
else
throw;
return default(T); // or throw?
}
}
protected override void Cancel(AsyncCodeActivityContext context)
{
var cts = (CancellationTokenSource)context.UserState;
cts.Cancel();
}
protected abstract Task<T> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken);
}
शानदार उत्तर! धन्यवाद! – fra
एक छोटी अतिरिक्त आवश्यकता: मुझे आवश्यक एसिंक गतिविधि को एक पिक गतिविधि में एक संभावित ट्रिगर माना जाता है, इसलिए मुझे रद्दीकरण (सुंदर) रद्दीकरण की भी आवश्यकता है ... इस तरह के परिदृश्य का समर्थन करने के लिए इसे कैसे बढ़ाया जा सकता है? धन्यवाद – fra
मैं डब्ल्यूएफ रद्दीकरण से परिचित नहीं हूं, लेकिन मुझे आशा है कि आप 'ExecuteAsync' को टोकन पास करने के दौरान 'BeginExecute' (और संदर्भ में इसे सहेज लें) में' रद्दीकरण टोकन स्रोत 'बना सकते हैं। फिर संदर्भ से 'रद्दीकरण टोकन स्रोत' प्राप्त करने के लिए 'रद्द करें' ओवरराइड करें, इसे रद्द करें, और 'मार्ककैंक्ड' पर कॉल करें। –