C # संदर्भों की वापसी का समर्थन क्यों नहीं करता है?


141

मैंने पढ़ा है कि .NET संदर्भों की वापसी का समर्थन करता है, लेकिन C # नहीं। क्या कोई खास वजह है? मैं ऐसा क्यों नहीं कर सकता:

static ref int Max(ref int x, ref int y) 
{ 
  if (x > y) 
    return ref x; 
  else 
    return ref y; 
} 

8
उम ... प्रशस्ति पत्र कृपया?
RPM1984

5
C # में मान और संदर्भ प्रकार होते हैं और दोनों को वापस लौटाया जा सकता है।
जूनुन

मैं कुछ इस तरह की बात कर रहा हूँreturn ref x
टॉम सरयू

2
4 वर्षों के बाद, आप इसे C# 7:) के साथ ठीक कर सकते हैं
अर्घ्य सी

जवाबों:


188

यह प्रश्न 23 जून 2011 को मेरे ब्लॉग का विषय था । महान प्रश्न के लिए धन्यवाद!

C # टीम C # 7 के लिए इस पर विचार कर रही है । विवरण के लिए https://github.com/dotnet/roslyn/issues/5233 देखें।

अद्यतन: सुविधा ने इसे C # 7 में बनाया है!


तुम सही हो; .NET ऐसे तरीकों का समर्थन करता है जो चर के लिए प्रबंधित संदर्भ लौटाते हैं । .NET स्थानीय चर का भी समर्थन करता है जिसमें अन्य चर के लिए प्रबंधित संदर्भ होते हैं। (ध्यान दें कि .NET उन फ़ील्ड्स या सरणियों का समर्थन नहीं करता है जिनमें अन्य चर के लिए प्रबंधित संदर्भ शामिल हैं क्योंकि यह कचरा संग्रह कहानी को जटिल बनाता है। "प्रबंधित संदर्भ चर" प्रकार भी ऑब्जेक्ट के लिए परिवर्तनीय नहीं हैं , और इसलिए इसका उपयोग नहीं किया जा सकता है। जेनेरिक प्रकार या विधियों के लिए तर्क टाइप करें।)

टिप्पणीकार "RPM1984" ने किसी कारण से इस तथ्य के लिए प्रशस्ति पत्र मांगा। RPM1984 मैं आपको .NET की इस सुविधा के बारे में जानकारी के लिए CLI विनिर्देश विभाजन I खंड 8.2.1.1, "प्रबंधित संकेत और संबंधित प्रकार" पढ़ने के लिए प्रोत्साहित करता हूं।

सी # का एक संस्करण बनाना पूरी तरह से संभव है जो इन दोनों विशेषताओं का समर्थन करता है। आप तब जैसी चीजें कर सकते थे

static ref int Max(ref int x, ref int y) 
{ 
  if (x > y) 
    return ref x; 
  else 
    return ref y; 
} 

और फिर इसके साथ कॉल करें

int a = 123;
int b = 456; 
ref int c = ref Max(ref a, ref b); 
c += 100;
Console.WriteLine(b); // 556!

मैं अनुभवजन्य रूप से जानता हूं कि C # का एक संस्करण बनाना संभव है जो इन विशेषताओं का समर्थन करता है क्योंकि मैंने ऐसा किया है । उन्नत प्रोग्रामर, विशेष रूप से अप्रबंधित सी ++ कोड को पोर्ट करने वाले लोग, अक्सर हमसे अधिक सी ++ के लिए पूछते हैं - जैसे कि संदर्भ के साथ चीजों को करने की क्षमता, वास्तव में पॉइंटर्स का उपयोग करके और सभी जगह मेमोरी को पिन करने के बिना। प्रबंधित संदर्भों का उपयोग करके आप अपने कचरा संग्रहण प्रदर्शन को खराब करने की लागत का भुगतान किए बिना ये लाभ प्राप्त करते हैं।

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

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

ref int M1(ref int x)
{
    return ref x;
}

ref int M2()
{
    int y = 123;
    return ref M1(ref y); // Trouble!
}

int M3()
{
    ref int z = ref M2();
    return z;
}

एम 3 एम 2 के स्थानीय चर की सामग्री लौटाता है, लेकिन उस चर का जीवनकाल समाप्त हो गया है! एक डिटेक्टर लिखना संभव है जो रिफ-रिटर्न के उपयोग को निर्धारित करता है जो स्पष्ट रूप से स्टैक सुरक्षा का उल्लंघन नहीं करता है। हम क्या करेंगे इस तरह के डिटेक्टर को लिखें, और यदि डिटेक्टर स्टैक सुरक्षा को साबित नहीं कर सकता है, तो हम प्रोग्राम के उस हिस्से में रेफ रिटर्न के उपयोग की अनुमति नहीं देंगे। यह करने के लिए देव कार्य की एक बड़ी राशि नहीं है, लेकिन यह सुनिश्चित करने के लिए परीक्षण टीमों पर बहुत अधिक बोझ है कि हमें वास्तव में सभी मामले मिल गए हैं। यह सिर्फ एक और बात है जो सुविधा की लागत को उस बिंदु तक बढ़ाती है जहां अभी लाभ लागत से अधिक नहीं है।

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

(संबंधित प्रश्न भी देखें क्या C # में चर के संदर्भ को वापस करना संभव है? और क्या मैं C # फ़ंक्शन जैसे C ++ के अंदर संदर्भ का उपयोग कर सकता हूं? )


4
@EricLippert: मेरे पास कोई ठोस उदाहरण नहीं है बस कुछ है जो मैं सोच रहा था। उत्कृष्ट और सम्मोहक प्रतिक्रिया
टॉम सरयू

1
@ एरिक: आपके बहिष्करण में, लौटने के बाद y जीवित रखने के लिए अधिक उपयुक्त नहीं होगा M2? मुझे उम्मीद है कि यह सुविधा स्थानीय लोगों को पकड़ने वाले लंबोदर की तरह काम करेगी। या आपके द्वारा प्रस्तावित व्यवहार क्योंकि यह सीएलआर उस परिदृश्य को कैसे संभालता है?
फेड

3
@ ईरिक: IMHO गुण प्रकार के संदर्भ मान रखने की क्षमता .net भाषाओं में एक प्रमुख चूक है। यदि Arr एक मान प्रकार (जैसे बिंदु) का एक सरणी है, तो कोई कह सकता है जैसे Arr (3) .X = 9 और पता है कि किसी ने Arr (9) .X या यहां तक ​​कि SomeOtherArray (2) का मान नहीं बदला है। एक्स; यदि Arr कुछ संदर्भ प्रकार की एक सरणी के बजाय होता, तो ऐसी कोई गारंटी नहीं होती। तथ्य यह है कि एक सरणी का अनुक्रमण ऑपरेटर एक संदर्भ देता है, अत्यंत उपयोगी है; मैं इसे बहुत दुर्भाग्यपूर्ण मानता हूं कि कोई अन्य प्रकार का संग्रह ऐसी कार्यक्षमता प्रदान नहीं कर सकता है।
सुपरकैट

4
एरिक, परिदृश्यों के संबंध में फीडबैक प्रदान करने का सबसे अच्छा तरीका क्या है (जैसा कि आप अंतिम पैराग्राफ में सुझाव देते हैं) यह देखने के अवसरों को अधिकतम करने के लिए? एमएस कनेक्ट? UserVoice (अपनी मनमानी 10 पोस्ट / वोट सीमा के साथ)? कुछ और?
रोमन स्टार्कोव

1
@ThunderGr: यह "असुरक्षित" के लिए C # दर्शन है - यदि आप ऐसा कोड लिखते हैं जो संभवतः मेमोरी-असुरक्षित है तो C # जोर देता है कि आप इसे "असुरक्षित" के रूप में चिह्नित करते हैं, जिससे आप मेमोरी सुरक्षा की जिम्मेदारी ले रहे हैं। C # में पहले से ही सुविधा का असुरक्षित संस्करण है, बशर्ते कि प्रश्न में चर अप्रबंधित प्रकार का हो। सवाल यह है कि क्या सी # टीम को एक असुरक्षित संस्करण बनाना चाहिए जो प्रबंधित प्रकारों को संभालता है। यदि ऐसा करने से डेवलपर के लिए भयानक कीड़े लिखना आसान हो जाता है, तो ऐसा होने वाला नहीं है। सी # सी ++ नहीं है, एक ऐसी भाषा है जो भयानक कीड़े लिखना आसान बनाती है। C # डिजाइन द्वारा सुरक्षित है।
एरिक लिपर्ट

21

आप उन विधियों के बारे में बात कर रहे हैं जो एक मान प्रकार के लिए एक संदर्भ लौटाते हैं। C # में निर्मित एकमात्र उदाहरण जो मुझे पता है कि मूल्य प्रकार का सरणी-अभिगमक है:

public struct Point
{
    public int X { get; set; }
    public int Y { get; set; }
}

और अब उस संरचना का एक सरणी बनाएँ:

var points = new Point[10];
points[0].X = 1;
points[0].Y = 2;

इस मामले में points[0], सरणी अनुक्रमणिका , संरचना के संदर्भ में लौट रही है। अपने खुद के इंडेक्सर (उदाहरण के लिए एक कस्टम संग्रह) लिखना असंभव है , जिसमें यह "एक संदर्भ लौटाएं" व्यवहार है।

मैंने C # भाषा डिज़ाइन नहीं की थी, इसलिए मुझे इसका समर्थन न करने के पीछे के सभी तर्क नहीं पता हैं, लेकिन मुझे लगता है कि इसका संक्षिप्त जवाब हो सकता है: हम इसके बिना बस ठीक हो सकते हैं।


8
टॉम उन तरीकों के बारे में पूछ रहा है जो एक चर का संदर्भ देते हैं । परिवर्तनीय की आवश्यकता मूल्य प्रकार की नहीं होनी चाहिए, हालांकि यह है कि आमतौर पर लोग वही चाहते हैं जब वे रिफंड-वापसी के तरीके चाहते हैं। अन्यथा, महान विश्लेषण; आप सही हैं कि C # भाषा में एकमात्र स्थान जहां एक जटिल अभिव्यक्ति एक रेफरी को एक चर के लिए उत्पन्न करता है जिसे उपयोगकर्ता तब हेरफेर कर सकता है वह सरणी अनुक्रमणिका है। (और निश्चित रूप से सदस्य पहुंच ऑपरेटर ""। एक रिसीवर और एक क्षेत्र के बीच, लेकिन यह स्पष्ट रूप से एक चर के लिए एक पहुँच है।)
एरिक लिपर्ट

1

आप हमेशा कुछ ऐसा कर सकते हैं:

public delegate void MyByRefConsumer<T>(ref T val);

public void DoSomethingWithValueType(MyByRefConsumer<int> c)
{
        int x = 2;
        c(ref x);
        //Handle potentially changed x...
}

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.