प्रॉपर्टी या इंडेक्स को आउट या रेफ पैरामीटर के रूप में पारित नहीं किया जा सकता है


86

मुझे उपरोक्त त्रुटि मिल रही है और इसे हल करने में असमर्थ हूं। मैं थोडा गुग गया लेकिन इससे छुटकारा नहीं पाया।

परिदृश्य:

मेरे पास वर्ग बजट है, जिसकी संपत्ति बजट है जो दोहरे प्रकार का है।

मेरे डेटाअबलेयर में,

मेरी एक कक्षा में मैं यह करने की कोशिश कर रहा हूँ:

double.TryParse(objReader[i].ToString(), out bd.Budget);

जो इस त्रुटि को फेंक रहा है:

संपत्ति या अनुक्रमणिका को संकलन समय पर आउट या रेफ पैरामीटर के रूप में पारित नहीं किया जा सकता है।

मैंने भी यह कोशिश की:

double.TryParse(objReader[i].ToString().Equals(DBNull.Value) ? "" : objReader[i].ToString(), out bd.Budget);

बाकी सब कुछ ठीक काम कर रहा है और परतों के बीच संदर्भ मौजूद हैं।


Bd.Budget bd में क्लास BudgetAllocate की एक वस्तु है। माफ करना मैं भूल गया।
प्रतीकात्मक निर्णय




बस इसे एक उपयोगकर्ता प्रकार के साथ काम करने की खोज की जिसमें खेतों को परिभाषित किया गया था जो कि मुझे उम्मीद थी कि इसके DataGridबाद से आबादी होगी यह केवल गुणों के साथ ऑटोस सीखना है। संपत्तियों पर स्विच करने से कुछ रिफ पैरामीटर टूट गए, जिनका मैं अपने खेतों में उपयोग कर रहा था। के साथ पार्स करने के लिए स्थानीय चर को परिभाषित करेगा।
jxramos

जवाबों:


37

आप उपयोग नहीं कर सकते

double.TryParse(objReader[i].ToString(), out bd.Budget); 

bd.Budget को कुछ वैरिएबल से बदलें।

double k;
double.TryParse(objReader[i].ToString(), out k); 

11
एक अतिरिक्त चर का उपयोग क्यों करें ??
प्रत्यूष

6
@pratik आप किसी पैरामीटर के रूप में किसी प्रॉपर्टी में पास नहीं हो सकते क्योंकि इस बात की कोई गारंटी नहीं है कि प्रॉपर्टी में वास्तव में एक सेटर है, इसलिए आपको अतिरिक्त वैरिएबल की आवश्यकता है।
मैट

23
@ mjd79: आपका तर्क गलत है। कंपाइलर जानता है कि एक सेटर है या नहीं। मान लीजिए कि एक सेटर था; क्या इसकी अनुमति होनी चाहिए?
एरिक लिपर्ट

21
@ दिनेश, मुझे लगता है कि ओपी इस बात का जवाब ढूंढ रहा है कि वह ऐसा क्यों नहीं कर सकता है, न कि उसे इसके बजाय क्या करना चाहिए। हंस पसंत का जवाब और एरिक लिपर्ट की टिप्पणी पढ़ें।
स्लगस्टर

2
@ दिनेश "असली" कारण वह ऐसा नहीं कर सकता है क्योंकि वह VB के बजाय C # का उपयोग कर रहा है जो इसे अनुमति नहीं देता है। मैं VB दुनिया से हूँ (स्पष्ट रूप से?) और मैं अक्सर अतिरिक्त प्रतिबंध C # imposes पर हैरान हूं।
स्टीव डिकिन

149

दूसरों ने आपको समाधान दिया है, लेकिन जैसा कि यह क्यों आवश्यक है: एक संपत्ति एक विधि के लिए सिर्फ वाक्यविन्यास चीनी है ।

उदाहरण के लिए, जब आप Nameहुड के नीचे एक गेटटर और सेटर के साथ एक संपत्ति घोषित करते हैं , तो कंपाइलर वास्तव में बुलाया विधियों को उत्पन्न करता है get_Name()और set_Name(value)। फिर, जब आप इस संपत्ति से पढ़ते हैं और लिखते हैं, तो संकलक इन कार्यों को उन उत्पन्न विधियों में कॉल में अनुवाद करता है।

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

इंडेक्सर्स के लिए एक समान मामला मौजूद है।


19
आपका तर्क अंतिम बिट तक सही है। आउट पैरामीटर किसी वैरिएबल के संदर्भ की अपेक्षा कर रहा है , न कि किसी ऑब्जेक्ट के लिए
एरिक लिपर्ट

@ EricLippert लेकिन एक चर भी एक वस्तु नहीं है या मुझे क्या याद आ रही है?
meJustAndrew

6
@meJustAndrew: एक चर बिल्कुल एक वस्तु नहीं है । एक चर एक भंडारण स्थान है । भंडारण स्थान में या तो (1) संदर्भ प्रकार की वस्तु (या अशक्त) का संदर्भ होता है, या (2) मूल्य प्रकार की वस्तु का मूल्य। इसमें निहित चीज़ के लिए कंटेनर को भ्रमित न करें।
एरिक लिपर्ट

6
@meJustAndrew: एक वस्तु पर विचार करें, कहते हैं, एक घर। उस कागज के टुकड़े पर विचार करें, जिस पर घर का पता लिखा हो। एक दराज पर विचार करें जिसमें कागज का वह टुकड़ा हो। न तो दराज और न ही कागज घर हैं
एरिक लिपर्ट

69

यह एक लीक से हटकर मामला है। एक संपत्ति वास्तव में एक विधि है, इंडेक्सर के लिए प्राप्त और सेट एक्सेसर्स get_Index () और set_Index विधियों के लिए संकलित हो जाते हैं। कंपाइलर उस तथ्य को छिपाते हुए एक भयानक काम करता है, यह उदाहरण के लिए स्वचालित रूप से संबंधित set_Xxx () पद्धति के लिए एक संपत्ति में असाइनमेंट का अनुवाद करता है।

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

उल्लेखनीय है कि यह वास्तव में VB.NET में काम करता है। उदाहरण के लिए:

Class Example
    Public Property Prop As Integer

    Public Sub Test(ByRef arg As Integer)
        arg = 42
    End Sub

    Public Sub Run()
        Test(Prop)   '' No problem
    End Sub
End Class

VB.NET कंपाइलर C # में व्यक्त रन विधि के लिए स्वचालित रूप से इस कोड को उत्पन्न करके इसे हल करता है:

int temp = Prop;
Test(ref temp);
Prop = temp;

जो कि वर्कअराउंड है जिसे आप भी इस्तेमाल कर सकते हैं। यह निश्चित नहीं है कि C # टीम ने एक ही दृष्टिकोण का उपयोग क्यों नहीं किया। संभवतः क्योंकि वे संभावित रूप से महंगे गेट्टर और सेटर कॉल को छिपाना नहीं चाहते थे। या सेटर द्वारा पूरी तरह से अनुचित व्यवहार करने पर आपको मिलेगा कि सेटर के साइड-इफेक्ट्स हैं जो संपत्ति के मूल्य को बदलते हैं, वे असाइनमेंट के बाद गायब हो जाएंगे। C # और VB.NET के बीच क्लासिक अंतर है, C # "कोई आश्चर्य नहीं" है, VB.NET "यह काम करें यदि आप कर सकते हैं"।


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

2
वास्तव में जिस चीज की आवश्यकता होती है वह है पैरामीटर-पासिंग मोड्स की एक बड़ी विविधता, ताकि कंपाइलर "कॉपी / इन / कॉपी आउट" को स्थानापन्न कर सके, जहां उपयुक्त हो, लेकिन उन मामलों में स्क्वॉक करें जहां यह नहीं है।
सुपर स्टार

9

स्थानीय पैरामीटर में बाहर पैरामीटर रखें और फिर चर को इसमें सेट करें bd.Budget:

double tempVar = 0.0;

if (double.TryParse(objReader[i].ToString(), out tempVar))
{
    bd.Budget = tempVar;
}

अपडेट : MSDN से सीधे:

गुण परिवर्तनशील नहीं हैं और इसलिए इन्हें बाहर के मापदंडों के रूप में पारित नहीं किया जा सकता है।


1
@ E.vanderSpoel सौभाग्य से मैंने सामग्री को हटा दिया, लिंक हटा दिया।
एडम हल्ड्सवर्थ

8

संभवत: रुचि - आप अपना लिख ​​सकते हैं:

    //double.TryParse(, out bd.Budget);
    bool result = TryParse(s, value => bd.Budget = value);
}

public bool TryParse(string s, Action<double> setValue)
{
    double value;
    var result =  double.TryParse(s, out value);
    if (result) setValue(value);
    return result;
}

5

यह एक बहुत पुरानी पोस्ट है, लेकिन मैं स्वीकार कर रहा हूँ, क्योंकि ऐसा करने का एक और भी शानदार तरीका है जो मुझे नहीं पता था।

इसे इनलाइन घोषणा कहा जाता है और यह हमेशा उपलब्ध होता है (जैसे कि स्टेटमेंट का उपयोग करके) या यह ऐसे मामलों के लिए C # 6.0 या C # 7.0 के साथ जोड़ा जा सकता है, निश्चित नहीं है, लेकिन वैसे भी एक आकर्षण की तरह काम करता है:

इसी का इत्तफाक

double temp;
double.TryParse(objReader[i].ToString(), out temp);
bd.Budget = temp;

इसे इस्तेमाल करो:

double.TryParse(objReader[i].ToString(), out double temp);
bd.Budget = temp;

2
यदि अमान्य इनपुट के मामले में तोता सफल रहा, तो मैं जांच के लिए रिटर्न का उपयोग करूंगा।
मार्सेलडेव

1

तो बजट एक संपत्ति है, सही है?

इसके बजाय पहले इसे एक स्थानीय चर पर सेट करें, और फिर उस पर गुण मान सेट करें।

double t = 0;
double.TryParse(objReader[i].ToString(), out t); 
bd.Budget = t;

धन्यवाद। लेकिन मैं ऐसा क्यों जान सकता हूँ?
प्रत्यूष

0

आमतौर पर जब मैं ऐसा करने की कोशिश कर रहा होता हूं, क्योंकि मैं अपनी संपत्ति सेट करना चाहता हूं या डिफ़ॉल्ट मूल्य पर छोड़ना चाहता हूं। इस उत्तर और dynamicप्रकारों की मदद से हम इसे एक पंक्तिबद्ध और सरल रखने के लिए आसानी से एक स्ट्रिंग विस्तार विधि बना सकते हैं।

public static dynamic ParseAny(this string text, Type type)
{
     var converter = TypeDescriptor.GetConverter(type);
     if (converter != null && converter.IsValid(text))
          return converter.ConvertFromString(text);
     else
          return Activator.CreateInstance(type);
}

ऐसे उपयोग करो;

bd.Budget = objReader[i].ToString().ParseAny(typeof(double));

// Examples
int intTest = "1234".ParseAny(typeof(int)); // Result: 1234
double doubleTest = "12.34".ParseAny(typeof(double)); // Result: 12.34
decimal pass = "12.34".ParseAny(typeof(decimal)); // Result: 12.34
decimal fail = "abc".ParseAny(typeof(decimal)); // Result: 0
string nullStr = null;
decimal failedNull = nullStr.ParseAny(typeof(decimal)); // Result: 0

ऐच्छिक

साइड नोट पर, यदि SQLDataReaderआप GetSafeStringपाठक से अशक्त अपवादों से बचने के लिए एक्सटेंशन (एस) का उपयोग कर सकते हैं ।

public static string GetSafeString(this SqlDataReader reader, int colIndex)
{
     if (!reader.IsDBNull(colIndex))
          return reader.GetString(colIndex);
     return string.Empty;
}

public static string GetSafeString(this SqlDataReader reader, string colName)
{
     int colIndex = reader.GetOrdinal(colName);
     if (!reader.IsDBNull(colIndex))
          return reader.GetString(colIndex);
     return string.Empty;
}

ऐसे उपयोग करो;

bd.Budget = objReader.GetSafeString(i).ParseAny(typeof(double));
bd.Budget = objReader.GetSafeString("ColumnName").ParseAny(typeof(double));
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.