2008-10-17 7 views
7

मैं एक सी # विधि है जो एक विधेय < फू > स्वीकार करता है और मिलान मदों की एक सूची देता है ...कैशिंग प्रतिनिधि परिणाम

public static List<Foo> FindAll(Predicate<Foo> filter) 
{ 
    ... 
} 

फिल्टर अक्सर एक सामान्य सेट में से एक हो जाएगा ...

है
public static class FooPredicates 
{ 
    public static readonly Predicate<Foo> IsEligible = (foo => ...) 
    ... 
} 

... लेकिन एक अज्ञात प्रतिनिधि हो सकता है।

अब मैं इस विधि को एएसपी.NET कैश में अपने परिणाम कैश करना चाहता हूं, इसलिए उसी प्रतिनिधि के साथ बार-बार कॉल कैश किए गए परिणाम को वापस कर दें। इसके लिए, मुझे प्रतिनिधि से कैश कुंजी बनाना होगा। Delegate.GetHashCode() इस उद्देश्य के लिए समझदार परिणाम पैदा करेगा? क्या प्रतिनिधि के कुछ अन्य सदस्य हैं जिन्हें मुझे देखना चाहिए? क्या आप इसे एक और तरीका पूरी तरह से करेंगे?

उत्तर

4

अपना कैशिंग कार्य करने के लिए, आप अन्य सुझावों का पालन कर सकते हैं और < < Foo>, < Foo >> (ग्लोबल के लिए स्थिर, या सदस्य फ़ील्ड अन्यथा) परिणाम को कैश करते हैं। वास्तव में < Foo> को सक्रिय करने से पहले, आपको यह जांचना होगा कि परिणाम शब्दकोश में पहले से मौजूद है या नहीं।

इस नियतात्मक समारोह कैशिंग के लिए सामान्य नाम Memoization कहा जाता है - और उसके भयानक :)

जब से सी # 3.0 लैम्ब्डा की और समारोह/कार्रवाई प्रतिनिधियों की लूट कहा, सी # करने के लिए Memoization जोड़ने काफी आसान है।

वेस डायर का great post है जो कुछ महान उदाहरणों के साथ अवधारणा को सी # में लाता है।

यदि आप चाहते हैं कि मैं आपको यह दिखाऊं कि यह कैसे करना है, तो मुझे बताएं ... अन्यथा, वेस की पोस्ट पर्याप्त होनी चाहिए।

प्रतिनिधि हैश कोड के बारे में आपकी क्वेरी के जवाब में। यदि दो प्रतिनिधि समान हैं, d1.GetHashCode() को d2.GetHashCode() के बराबर होना चाहिए, लेकिन मैं इसके बारे में 100% नहीं हूं। आप ज्ञापन को जाने के द्वारा इसे जल्दी से देख सकते हैं, और अपनी FindAll विधि में एक WriteLine जोड़ सकते हैं। यदि यह सच नहीं होता है, तो दूसरा विकल्प Linq.Expression < का उपयोग करना है < Foo >> पैरामीटर के रूप में। अगर अभिव्यक्ति बंद नहीं होती है, तो अभिव्यक्ति जो एक ही चीज करती है वह बराबर होनी चाहिए।

मुझे बताएं कि यह कैसे जाता है, मुझे प्रतिनिधि के बारे में जवाब जानने में दिलचस्पी है। एक्वाल्स।

+0

मैंने नीचे जवाब दिया है प्रतिनिधियों के कुछ परीक्षणों के साथ। एक्वाल्स। मैं शायद सोमवार को अधिक जोड़ दूंगा जब मैं वास्तविक विचारों का उपयोग करने की कोशिश करता हूं। – stevemegson

2

आवेदक सूची में प्रत्येक आमंत्रण पर समान समानता दिखाई देती है, विधि की समानता के लिए परीक्षण, और विधि का लक्ष्य।

विधि कैश कुंजी का एक साधारण टुकड़ा है, लेकिन विधि का लक्ष्य (इसे उदाहरण के लिए कॉल करने का उदाहरण - एक आवृत्ति विधि मानना) एक क्रमिक तरीके से कैश करना असंभव हो सकता है। विशेष रूप से, अज्ञात कार्यों के लिए जो राज्य को पकड़ते हैं, यह उस राज्य को पकड़ने के लिए बनाए गए घोंसला वाले वर्ग का एक उदाहरण होगा।

यदि यह सब याद में है, तो प्रतिनिधि को खुद ही हैश कुंजी के रूप में रखना ठीक रहेगा - हालांकि इसका मतलब यह हो सकता है कि कुछ ऑब्जेक्ट्स जो क्लाइंट कचरा होने की उम्मीद करेंगे, वे चारों ओर लटकाएंगे। यदि आपको डेटाबेस में इसे क्रमबद्ध करने की आवश्यकता है, तो यह बालों वाली हो जाती है।

क्या आप अपनी विधि को कैश कुंजी (जैसे एक स्ट्रिंग) स्वीकार कर सकते हैं? (यह मान रहा है कि मेमोरी कैश में अपर्याप्त है।)

+0

"विधि कैश कुंजी का एक साधारण टुकड़ा है"। बहुत बुरा है। नेट विचित्र रूप से इसका उपयोग नहीं करता है। एक (सामान्य) प्रतिनिधि का हैश कोड केवल अपनी आमंत्रण सूची में प्रतिनिधियों के प्रकार पर आधारित होता है। इसलिए, 4 ग्राहकों के साथ किसी भी 'एक्शन' प्रतिनिधि के पास एक ही हैश कोड है (http://stackoverflow.com/questions/6624151/why-do-2-delegate-instances-return-the-same-hashcode/6624255#6624255 –

1

जब तक आप सुनिश्चित न हों कि GetHashCode का प्रतिनिधि का कार्यान्वयन निर्धारिती है और इसके परिणामस्वरूप कोई टकराव नहीं होता है, तो मुझे विश्वास नहीं होगा।

यहां दो विचार हैं। सबसे पहले, प्रिंटर को कुंजी के रूप में भविष्यवाणी करते हुए प्रतिनिधियों के परिणामों को एक पूर्वानुमान/सूची शब्दकोश के भीतर संग्रहीत करें, और उसके बाद परिणामों के पूरे शब्दकोश को कैश में एक कुंजी के नीचे संग्रहीत करें। बुरी बात यह है कि यदि कैश आइटम गुम हो जाता है तो आप अपने सभी कैश किए गए परिणाम खो देते हैं।

एक विकल्प, भविष्यवाणी, GetKey() के लिए एक एक्सटेंशन विधि बनाना होगा, जो किसी ऑब्जेक्ट/स्ट्रिंग डिक्शनरी का उपयोग सभी भविष्यवाणियों के लिए सभी कुंजी को स्टोर और पुनर्प्राप्त करने के लिए करता है। आप प्रतिनिधि के साथ शब्दकोश में अनुक्रमित करते हैं और इसकी कुंजी वापस करते हैं, अगर आपको यह नहीं मिलता है तो एक बनाते हैं। इस तरह आपको आश्वासन दिया जाता है कि आपको प्रति प्रतिनिधि सही कुंजी मिल रही है और कोई टक्कर नहीं है। एक naiive एक प्रकार का नाम + Guid होगा।

+0

प्रतिनिधि समानता (और हैश कोड) ठीक काम करता है यदि आप प्रतिनिधि को सीधे शब्दकोश में कुंजी के रूप में स्टोर करने में सक्षम हैं। समस्या तब आती है जब आपको किसी भी तरह से स्मृति से मानचित्र प्राप्त करना पड़े। –

0

किसी ऑब्जेक्ट का एक ही उदाहरण हमेशा एक ही हैशकोड (.NET में GetHashCode() की आवश्यकता को वापस कर देगा। यदि आपकी भविष्यवाणियां एक स्थिर सूची के अंदर हैं और आप उन्हें हर बार फिर से परिभाषित नहीं कर रहे हैं, तो मुझे चाबियों के रूप में उपयोग करने में कोई समस्या नहीं दिखाई दे रही है।

2

एक शब्दकोश < विधेय < फू>, सूची < फू >> में कैश परिणाम रखते हुए मेरे लिए अजीब है क्योंकि मैं ASP.NET कैश नहीं बल्कि सभी परिणाम हमेशा के लिए कैशिंग तुलना में मेरे लिए समाप्ति हैंडल करना चाहते है, लेकिन यह किसी भी तरह से है अच्छा समाधान। मुझे लगता है कि मैं विल के डिक्शनरी < के साथ जा रहा हूंफू> स्ट्रिंग> एक स्ट्रिंग को कैश करने के लिए जिसे मैं ASP.NET कैश कुंजी में उपयोग कर सकता हूं।

कुछ शुरुआती परीक्षण बताते हैं कि प्रतिनिधि समानता "सही चीज़" करती है जैसे कि अन्य ने कहा है, लेकिन प्रतिनिधि। गेटहाशकोड रोगजनक रूप से अनुपयोगी है। परावर्तक

public override int GetHashCode() 
{ 
    return base.GetType().GetHashCode(); 
} 

इसलिए किसी भी विधेय < फू> एक ही परिणाम देता है पता चलता है।

मेरा शेष मुद्दा यह था कि अज्ञात प्रतिनिधियों के लिए समानता कैसे काम करती है। तब "एक ही लक्ष्य पर एक ही विधि कहा जाता है" का मतलब क्या है? ऐसा लगता है कि जब तक प्रतिनिधि को उसी स्थान पर परिभाषित किया गया था, संदर्भ बराबर हैं। अलग-अलग स्थानों में परिभाषित एक ही शरीर के साथ प्रतिनिधि नहीं हैं।

static Predicate<int> Test() 
{ 
    Predicate<int> test = delegate(int i) { return false; }; 
    return test; 
} 

static void Main() 
{ 
    Predicate<int> test1 = Test(); 
    Predicate<int> test2 = Test(); 
    Console.WriteLine(test1.Equals(test2)); // True 

    test1 = delegate(int i) { return false; }; 
    test2 = delegate(int i) { return false; }; 
    Console.WriteLine(test1.Equals(test2)); // False 
} 

यह मेरी आवश्यकताओं के लिए ठीक होना चाहिए। पूर्वनिर्धारित भविष्यवाणियों के साथ कॉल कैश किया जाएगा। एक विधि को एकाधिक कॉल जो किसी अज्ञात विधि के साथ FindAll को कॉल करता है उसे कैश किए गए परिणाम प्राप्त करना चाहिए। FindAll को कॉल करने के दो तरीके स्पष्ट रूप से वही अनाम विधि के साथ कैश्ड परिणाम साझा नहीं करेंगे, लेकिन यह काफी दुर्लभ होना चाहिए।

संबंधित मुद्दे