2009-07-20 12 views
10

मैं अभी भी रेफरी से गुज़रने के बारे में उलझन में हूं।रेफरी द्वारा पास?

यदि मेरे पास कैश ऑब्जेक्ट है जिसे मैं कई ऑब्जेक्ट्स तक एक्सेस/उपलब्ध करना चाहता हूं, और मैं इसे कन्स्ट्रक्टर इंजेक्शन का उपयोग करके इंजेक्ट करता हूं। मैं चाहता हूं कि यह मेरे द्वारा बनाई गई एकल कैश ऑब्जेक्ट को प्रभावित करे। जैसे।

public class Cache { 

    public void Remove(string fileToRemove) { 
     ... 
    } 
} 

public class ObjectLoader { 

    private Cache _Cache; 

    public ObjectLoader(Cache cache) { 

    } 

    public RemoveFromCacheFIleThatHasBeenDeletedOrSimilarOperation(string filename) { 
     _Cache.Remove(fileName); 
    } 
} 

क्या मैं ऑब्जेक्ट लोडर कन्स्ट्रक्टर में कैश पास करते समय रेफरी का उपयोग कर रहा हूं?

उत्तर

11

देखें कोई इस स्थिति में रेफरी कीवर्ड का उपयोग करने की जरूरत नहीं है।

कैश एक वर्ग है, यह एक संदर्भ प्रकार है। जब एक विधि में एक संदर्भ पारित किया जाता है, संदर्भ की एक प्रति (वस्तु स्वयं नहीं) आपके पैरामीटर में रखी जाती है। विधि के अंदर और बाहर दोनों संदर्भ ढेर पर एक ही वस्तु को इंगित कर रहे हैं, और किसी का उपयोग करके ऑब्जेक्ट के फ़ील्ड में संशोधन दूसरे में दिखाई देगा।

आपके विधि कॉल को रेफरी जोड़ना मूल संदर्भ में गुजरता है। यह ऐसी परिस्थिति में उपयोगी है जहां आपको पुन: असाइन किया जाएगा (यानी।new पर कॉल करके) संदर्भ बिंदु को कॉलिंग विधि के भीतर से इंगित करता है।

7

को संशोधित करने की आवश्यकता होने पर 'ref' कीवर्ड का उपयोग करें, संदर्भ पर इंगित करने वाला क्या है। जब आप किसी विधि में संदर्भ प्रकार पास करते हैं तो मान से गुजरता है, लेकिन मान उस संदर्भ के की प्रतिलिपि है जो विधि को पास किया गया है। इसका अर्थ यह है कि आप निर्दिष्ट वस्तु के सामान्य स्थिति (यानी, गुण/फ़ील्ड्स) को बदल सकते हैं, लेकिन यदि आप संदर्भ बिंदुओं को बदलने का प्रयास करते हैं तो आप केवल प्रति को प्रभावित करेंगे।

उदाहरण के लिए

, इस विधि को देखते हुए ...

private void Foo(MyClass obj) 
{ 
    obj = new MyClass(); 
    obj.SomeProperty = true; 
} 

हम तर्क में पारित कर सकते हैं और फिर देखें कि क्या वह प्रभावित था:

MyClass test = new MyClass(); 
test.SomeProperty = false; 
Foo(test); 
Console.WriteLine(test.SomeProperty); // prints "False" 

अब, अगर हम का उपयोग कर विधि परिभाषित किया था 'रेफरी' कीवर्ड ...

private void Foo(ref MyClass obj) 
{ 
    obj = new MyClass(); 
    obj.SomeProperty = true; 
} 

आउटपुट "सत्य" होगा, क्योंकि वास्तविक संदर्भ विधि को पारित किया गया था, एक प्रति नहीं। हमने फ़ंक्शन के भीतर उस संदर्भ बिंदु को बदल दिया है और हम उन परिवर्तनों के प्रभावों को देखते हैं।

जब आप 'रेफरी' कीवर्ड छोड़ देते हैं तो आप ढेर पर ऑब्जेक्ट पर एक नया पॉइंटर बना रहे हैं। यदि आप एक पॉइंटर बदलते हैं तो आप दूसरे को नहीं बदलेंगे।

...

तो, आपके सवाल का जवाब देना; नहीं, आपको किसी विधि को पारित होने पर आपके एकल कैश ऑब्जेक्ट की स्थिति बदलने के लिए 'ref' कीवर्ड का उपयोग करने की आवश्यकता नहीं है।

+0

यह सामान्य सी/सी ++ पॉइंटर्स के साथ इतना आसान है :) – Eugene

+1

मैं असहमत हूं :) लेकिन सी/सी ++ लोगों के लिए यह * (या &) और ** :) – Stormenet

+1

नाइटपिक के बीच का अंतर है: दूसरा उदाहरण - आप हैं एक स्थिर संपत्ति का उपयोग। – Cherian

-3

ऑब्जेक्ट्स स्वचालित रूप से संदर्भ द्वारा पारित होते हैं जब भी आप उन्हें .NET फ्रेमवर्क में फ़ंक्शन तर्कों में मान द्वारा पारित होने की घोषणा करते हैं।

ऐसा इसलिए है क्योंकि ऑब्जेक्ट स्वयं एक संदर्भ प्रकार है, इसलिए आप ऑब्जेक्ट के सदस्यों को संशोधित कर सकते हैं, भले ही आप ऑब्जेक्ट को प्रतिस्थापित नहीं कर सकते।

http://msdn.microsoft.com/en-us/library/aa903253(VS.71).aspx

+6

वस्तुओं को मूल्य से पारित किया जाता है, बस बाकी सब कुछ की तरह। वस्तुओं के साथ अंतर (पढ़ता है: संदर्भ प्रकार) यह है कि संदर्भ मूल्य से पारित किया जाता है। –

+2

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

1

मुझे लगता है कि आप सोच रहे हैं कि Cache ऑब्जेक्ट की कितनी प्रतियां बनाई जाएंगी। आप केवल एक कॉपी को कई क्लाइंट ऑब्जेक्ट्स द्वारा साझा करना चाहते हैं। खैर, एक बहुत ही सरल नियम है जिसे आप सी # में याद कर सकते हैं, जब भी आप जानना चाहते हैं कि आपकी ऑब्जेक्ट की कितनी अलग प्रतियां बनाई जाएंगी। साथ new कीवर्ड:

वस्तु के प्रकार साथ घोषित किया जाता है तो class कीवर्ड, तो केवल एक यह का एक नया उदाहरण बनाने के लिए रास्ता है।

इसमें मामूली अपवाद हैं: आप ऑब्जेक्ट बनाने वाले बीसीएल विधियों को कॉल कर सकते हैं, लेकिन बिंदु यह है कि यह स्पष्ट है। आपको विशेष रूप से ऐसा होने के लिए कहा जाना चाहिए। भाषा स्वचालित रूप से class ऑब्जेक्ट्स की प्रतियां नहीं बनायेगी।

तो अपने उदाहरण में, आप एक classCache कहा जाता है, और इसलिए आप कुछ के लिए पता है कि तुम चारों ओर प्रकार Cache के रूप में ज्यादा आप की तरह के रूप में, और Cache के आगे कोई प्रतियां बनाया जाएगा की चर पारित कर सकते हैं। उन सभी चरों जिनमें उन ऑब्जेक्ट को असाइन किया गया है, वही मूल ऑब्जेक्ट पर "पॉइंटिंग" होंगे। ऐसा इसलिए है क्योंकि Cache वैरिएबल ऑब्जेक्ट को स्वयं संग्रहित नहीं करता है, लेकिन स्मृति में Cache ऑब्जेक्ट का केवल स्थान है।

यदि आप class के बजाय struct प्रकार घोषित करते हैं तो इसके साथ क्या करें। अब जब आप उस प्रकार के चर को घोषित करते हैं, तो परिवर्तनीय को struct में घोषित सभी डेटा को स्टोर करने के लिए पर्याप्त होना चाहिए। प्रत्येक चर एक अलग प्रति है। प्रत्येक पैरामीटर एक अलग प्रति है।

आप ref कीवर्ड जोड़ कर इसे ओवरराइड कर सकते हैं, लेकिन यह अधिकांश कार्यक्रमों में एक बहुत ही असामान्य कीवर्ड है। out कीवर्ड अधिक आम है, और एक से अधिक रिटर्न मूल्य विधि देने के तरीके के रूप में सबसे अच्छा विचार किया जाता है।

ref पर कोई प्रभाव नहीं है यदि यह class प्रकार है? अपने उदाहरण में:

public ObjectLoader(Cache cache) { 
    // do stuff with cache (store it?) 
} 

मैं इस तरह दो वस्तु लोडर का निर्माण कर सकते हैं:

Cache c = new Cache(); 
ObjectLoader a = new ObjectLoader(c), 
ObjectLoader b = new ObjectLoader(c); 

हम सिर्फ कितने वस्तुओं बनाया? बस new कीवर्ड गिनें। अब, मान लीजिए हम ref कीवर्ड कहा:

public ObjectLoader(ref Cache cache) { 

    _cache = cache; // store   

    // do something very odd! 
    cache = new Cache(); 
} 

छिपा है कि निर्माता के अंदर, मैं एक और कैश बना लिया है, और पैरामीटर मैं पारित किया गया था में इसे संग्रहीत। चूंकि यह ref पैरामीटर है, इसलिए मैंने कॉलर के चर को प्रभावित किया है! बुला कोड में तो: संशोधित ObjectLoader निर्माता करने के लिए दो कॉल तीन से ऊपर स्निपेट में, प्लस:

Cache c = new Cache(); 
ObjectLoader a = new ObjectLoader(ref c), 
ObjectLoader b = new ObjectLoader(ref c); 

अब हम new के पांच इस्तेमाल होता है। प्रत्येक बार ObjectLoader के निर्माता को बुलाया जाता है, हम इसे c पास करते हैं। हमें ref कीवर्ड रखना है, जो एक बहुत अच्छी बात है क्योंकि इससे कोड पढ़ने वाले व्यक्ति को पता चलता है कि कुछ अजीब चल रहा है।परिवर्तनीय cObjectLoader के कन्स्ट्रक्टर रिटर्न के बाद एक अलग Cache पर इंगित करता है। तो b का ObjectLoader एक पॉइंटर को एक अलग Cache से a पर संग्रहीत करता है!

कहने की जरूरत नहीं है, यह कोड के लिए काफी गन्दा पैटर्न होगा। अगर हमें कॉलिंग साइट पर ref कीवर्ड डालना नहीं था तो यह और भी बदतर होगा!

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