मान लें कि आप पर TcpListener
class पर कॉल नहीं करना चाहते हैं, तो यहां कोई सही समाधान नहीं है।
आपको सूचित किया जा जब आपरेशन एक निश्चित समय सीमा के भीतर पूरा नहीं करता है, लेकिन मूल कार्य को पूरा करने के लिए अनुमति के साथ ठीक कर रहे हैं, तो आप एक विस्तार विधि बना सकते हैं जिससे की तरह:
public static async Task<T> WithWaitCancellation<T>(
this Task<T> task, CancellationToken cancellationToken)
{
// The tasck completion source.
var tcs = new TaskCompletionSource<bool>();
// Register with the cancellation token.
using(cancellationToken.Register(
s => ((TaskCompletionSource<bool>)s).TrySetResult(true), tcs))
// If the task waited on is the cancellation token...
if (task != await Task.WhenAny(task, tcs.Task))
throw new OperationCanceledException(cancellationToken);
// Wait for one or the other to complete.
return await task;
}
उपर्युक्त Stephen Toub's blog post "How do I cancel non-cancelable async operations?" से है।
चेतावनी यहाँ दोहरा भालू, यह वास्तव में कार्रवाई को रद्द नहीं करता, क्योंकि AcceptTcpClientAsync
method कि एक CancellationToken
लेता है की एक अधिभार नहीं है वहाँ है, यह रद्द कर दिया करने में सक्षम नहीं है।
इसका मतलब है कि विस्तार विधि इंगित करता है कि एक रद्द हो किया था, आप मूल Task
, नहीं की कॉलबैक पर इंतजार रद्द कर रहे हैं आपरेशन ही रद्द।
इसके लिए यही कारण है कि मैं संकेत मिलता है कि आप रद्द कर रहे हैं इंतजार, न कि वास्तविक कार्रवाई WithWaitCancellation
को WithCancellation
से विधि नाम दिया गया है।
वहाँ से, यह अपने कोड में उपयोग करने के लिए आसान है:
// Create the listener.
var tcpListener = new TcpListener(connection);
// Start.
tcpListener.Start();
// The CancellationToken.
var cancellationToken = ...;
// Have to wait on an OperationCanceledException
// to see if it was cancelled.
try
{
// Wait for the client, with the ability to cancel
// the *wait*.
var client = await tcpListener.AcceptTcpClientAsync().
WithWaitCancellation(cancellationToken);
}
catch (AggregateException ae)
{
// Async exceptions are wrapped in
// an AggregateException, so you have to
// look here as well.
}
catch (OperationCancelledException oce)
{
// The operation was cancelled, branch
// code here.
}
नोट आप होगा कि कॉल रैप करने के लिए अपने ग्राहक OperationCanceledException
उदाहरण यदि प्रतीक्षा रद्द कर दिया गया फेंक दिया पर कब्जा करने के लिए।
मैंने AggregateException
पकड़ में भी फेंक दिया है क्योंकि एसिंक्रोनस ऑपरेशंस से फेंकने पर अपवाद लपेटे जाते हैं (आपको इस मामले में स्वयं के लिए परीक्षण करना चाहिए)।
यह प्रश्न छोड़ देता है कि Stop
method (मूल रूप से, जो कुछ भी हो रहा है, चाहे वह क्या हो रहा है, चाहे वह कुछ भी नीचे आंसू हो), जो कि क्या हो रहा है, इस पर निर्भर करता है कि कौन सा दृष्टिकोण बेहतर दृष्टिकोण है। परिस्थितियों।
यदि आप उस संसाधन को साझा नहीं कर रहे हैं जिस पर आप इंतजार कर रहे हैं (इस मामले में, TcpListener
), तो संभवत: यह निरस्त विधि को कॉल करने के लिए संसाधनों का बेहतर उपयोग होगा और संचालन से आने वाले किसी भी अपवाद को निगल देगा इंतजार कर रहे हैं (जब आप स्टॉप को कॉल करते हैं तो आपको थोड़ा सा फ्लिप करना होगा और उस ऑपरेशन पर इंतजार कर रहे अन्य क्षेत्रों में उस बिट की निगरानी करें)। यह कोड में कुछ जटिलता जोड़ता है लेकिन यदि आप संसाधन उपयोग के बारे में चिंतित हैं और जितनी जल्दी हो सके सफाई कर रहे हैं, और यह विकल्प आपके लिए उपलब्ध है, तो यह जाने का तरीका है।
संसाधनों के उपयोग नहीं एक मुद्दा है और आप एक अधिक सहकारी तंत्र के साथ सहज महसूस करते हैं, और आप नहीं रहे संसाधन साझा करने, तो का उपयोग कर WithWaitCancellation
विधि ठीक है। यहां पेशेवर हैं कि यह क्लीनर कोड है, और बनाए रखने में आसान है।
आप 'completTask.GetAwaiter() का उपयोग क्यों करते हैं। केवल' पूरा टास्क। परिणाम 'के बजाय GetResult() '? –
@GlennSlayden यह पहले (यानी "असली") अपवाद फेंक देता है यदि 'टास्क। रिसेट' के विपरीत एक है जो 'एग्रीगेट एक्सेप्शन' – i3arnon
फेंकता है ठीक है, बढ़िया; धन्यवाद। क्या आप अपनी सहायक विस्तार विधि की पहली पंक्ति के रूप में 'रद्दीकरण टोकन। थ्रोइफ कैंसेलेशन रिक्वेस्टेड();' जोड़ना भी चाहते हैं? –