यदि आप Task
या Task<TResult>
से विरासत का फैसला करते हैं, आप हताशा कि Action<Object>
या Func<Object,TResult>
प्रतिनिधि उस कार्य निर्दिष्ट किया जाना चाहिए समय के लिए वास्तविक कार्य प्रदान करता है अपने कार्य व्युत्पन्न सामना कर सकते हैं वस्तु का निर्माण किया गया है, और बाद में बदला नहीं जा सकता है। यह सच है भले ही बेस क्लास कन्स्ट्रक्टर Start()
नव निर्मित कार्य नहीं करता है, और वास्तव में इसे तब तक शुरू नहीं किया जा सकता है जब तक कि कभी भी नहीं।
इससे Task
-स्थितियों में स्थित श्रेणी का उपयोग करना मुश्किल हो जाता है जहां उदाहरणों को अपने अंतिम कार्य के पूर्ण विवरण से पहले बनाया जाना चाहिए।
एक उदाहरण प्रसिद्ध Task<TResult>
एक साझा लक्ष्य पर काम कर नोड्स के एक अनाकार नेटवर्क हो सकता है ऐसी है कि वे एक तदर्थ ढंग से एक-दूसरे के Result
गुण का उपयोग। यह गारंटी देने का सबसे आसान तरीका है कि आप नेटवर्क में किसी भी मनमाने ढंग से नोड पर Wait()
कर सकते हैं, उनमें से किसी भी को शुरू करने से पहले उन सभी को पूर्व-निर्माण करना है। यह अच्छी तरह से कार्य ग्राफ निर्भरताओं का विश्लेषण करने की समस्या से बचाता है, और रनटाइम कारकों को यह निर्धारित करने की अनुमति देता है कि कब, यदि, और किस क्रम में Result
मानों की मांग की जाती है।
समस्या यह है कि, कुछ नोड्स के लिए, आप उस कार्य को प्रदान करने में सक्षम नहीं हो सकते हैं जो निर्माण समय पर कार्य को परिभाषित करता है। यदि आवश्यक लैम्ब्डा फ़ंक्शन बनाने के लिए नेटवर्क में अन्य कार्यों से Result
मानों को बंद करने की आवश्यकता है, तो Task<TResult>
जो Result
प्रदान करता है, हम चाहते हैं कि अभी तक निर्माण नहीं किया गया हो। और यहां तक कि अगर पूर्व निर्माण चरण के दौरान पहले इसका निर्माण किया गया था, तो भी आप Start()
पर कॉल नहीं कर सकते हैं क्योंकि यह अन्य नोड्स पर निर्भरता को शामिल कर सकता है। याद रखें, नेटवर्क की पूर्व-निर्माण का पूरा बिंदु इन तरह की जटिलताओं से बचना था।
जैसे कि यह पर्याप्त नहीं था, वांछित फ़ंक्शन प्रदान करने के लिए लैम्ब्डा फ़ंक्शन का उपयोग करने के लिए असुविधाजनक अन्य कारण भी हैं। चूंकि इसे कन्स्ट्रक्टर में तर्क के रूप में पारित किया गया है, इसलिए फ़ंक्शन वर्तमान कार्य उदाहरण के this
पॉइंटर तक नहीं पहुंच सकता है, जो बदसूरत कोड बनाता है, विशेष रूप से लैम्ब्डा को ध्यान में रखते हुए आवश्यक रूप से परिभाषित किया जाता है - और संभवतः अनजान बंद- कुछ असंबंधित this
सूचक।
मैं आगे बढ़ सकता था, लेकिन नीचे की रेखा यह है कि आपको व्युत्पन्न कक्षा में विस्तारित कार्यक्षमता को परिभाषित करते समय रनटाइम क्लोजर ब्लोट और अन्य परेशानी सहन नहीं करना चाहिए। क्या वह बहुरूपता के पूरे बिंदु को याद नहीं करता है? यह Task
के कार्य प्रतिनिधि को सामान्य तरीके से परिभाषित करने के लिए अधिक सुरुचिपूर्ण होगा, अर्थात्, बेस क्लास में एक अमूर्त कार्य।
यहां यह कैसे करें। यह चाल एक निजी कन्स्ट्रक्टर को परिभाषित करना है जो अपने स्वयं के तर्कों में से एक को बंद कर देता है। तर्क, शुरुआत में null
पर सेट किया गया है, प्लेसहोल्डर वैरिएबल के रूप में कार्य करता है जिसे आप Task
बेस क्लास द्वारा आवश्यक प्रतिनिधि बनाने के लिए बंद कर सकते हैं। एक बार जब आप कन्स्ट्रक्टर बॉडी में हों, तो 'यह' पॉइंटर उपलब्ध होगा, ताकि आप वास्तविक फ़ंक्शन पॉइंटर में पैच कर सकें।
'टास्क' से पाने के लिए: 'टास्क <TResult>' से पाने के लिए
public abstract class DeferredActionTask : Task
{
private DeferredActionTask(DeferredActionTask _this)
: base(_ => ((Func<DeferredActionTask>)_)().action(),
(Func<DeferredActionTask>)(() => _this))
{
_this = this;
}
protected DeferredActionTask() : this(null) { }
protected abstract void action();
};
:
public abstract class DeferredFunctionTask<TResult> : Task<TResult>
{
private DeferredFunctionTask(DeferredFunctionTask<TResult> _this)
: base(_ => ((Func<DeferredFunctionTask<TResult>>)_)().function(),
(Func<DeferredFunctionTask<TResult>>)(() => _this))
{
_this = this;
}
protected DeferredFunctionTask() : this(null) { }
protected abstract TResult function();
};
[संपादित करें: सरलीकृत]
ये सरलीकृत संस्करण व्युत्पन्न उदाहरणों 'कार्रवाई या फ़ंक्शन विधि पर सीधे बंद करके बाहरी बंद करने को कम करते हैं। यदि आप इसका उपयोग करना चाहते हैं तो यह बेस क्लास में AsyncState
को भी मुक्त करता है। यह शायद ही जरूरी लगता है क्योंकि अब आपकी अपनी पूरी व्युत्पन्न कक्षा है; तदनुसार, AsyncState
कार्य समारोह में पारित नहीं किया गया है। यदि आपको इसकी ज़रूरत है, तो आप हमेशा बेस क्लास पर संपत्ति से इसे पकड़ सकते हैं। अंत में, विभिन्न वैकल्पिक पैरामीटर अब Task
बेस क्लास के माध्यम से पारित किए जा सकते हैं।
'टास्क' से पाने के लिए:
public abstract class DeferredActionTask : Task
{
private DeferredActionTask(Action _a, Object state, CancellationToken ct, TaskCreationOptions opts)
: base(_ => _a(), state, ct, opts)
{
_a = this.action;
}
protected DeferredActionTask(
Object state = null,
CancellationToken ct = default(CancellationToken),
TaskCreationOptions opts = TaskCreationOptions.None)
: this(default(Action), state, ct, opts)
{
}
protected abstract void action();
};
'टास्क <TResult>' से पाने के लिए: एक async की
public abstract class DeferredFunctionTask<TResult> : Task<TResult>
{
private DeferredFunctionTask(Func<TResult> _f, Object state, CancellationToken ct, TaskCreationOptions opts)
: base(_ => _f(), state, ct, opts)
{
_f = this.function;
}
protected DeferredFunctionTask(
Object state = null,
CancellationToken ct = default(CancellationToken),
TaskCreationOptions opts = TaskCreationOptions.None)
: this(default(Func<TResult>), state, ct, opts)
{
}
protected abstract TResult function();
};
'टास्क.एसिंकस्टेट' के लिए धन्यवाद, मुझे इसके बारे में पता नहीं था। मैं केवल चिंतित हूं कि यह क्यों ऑब्जेक्ट करता है? कोई इसे ओवरराइड कर सकता है। –
@ माइक चाली का उद्देश्य IAsyncResult को लागू करने के लिए है, और केवल पढ़ा जाता है। एक बार जब आप अपना काम तैयार करेंगे तो कोई भी इसे आप पर ओवरराइड नहीं कर सकता है। इस सेट को प्राप्त करने के लिए आपको 'एक्शन' के बजाय' एक्शन 'ले जाने वाले रचनाकारों में से एक का उपयोग करके कार्य का निर्माण करने की आवश्यकता है ... –
@ReedCopsey ups, हाँ, आप सही हैं। खैर, फिर भी अच्छा लगता है। –