2009-03-13 14 views
5

मुझे कुछ सरल रैपर वर्ग के साथ समस्या है।सी # नकल असाइनमेंट ऑपरेटर को ओवरराइड कर रहा है (=)

यह इस तरह दिखता है:

public class Wrapper<T> 
{ 
    private T _value; 

    public Wrapper<T>(T value) 
    { 
    _value = value; 
    } 

    public static implicit operator Wrapper<T>(T value) 
    { 
    return new Wrapper<T>(value); 
    } 

    public static implicit operator T(Wrapper<T> value) 
    { 
    return value._value; 
    } 
} 

मैं से और टी करने के लिए अंतर्निहित कन्वर्टर्स ओवरराइड किया है, इसलिए यह लगभग टी खुद का एक उदाहरण की तरह व्यवहार करता है।

उदा।

Wrapper<int> foo = 42; 

हालांकि मैं एक मामूली समस्या है जब दूसरे के लिए आवरण का एक उदाहरण बताए, के बाद से मैं सिर्फ दूसरा आवरण वर्ग के मान देना चाहते हैं मिल गया है।

तो अभी, मैं यह करने के लिए है:

Wrapper<int> foo = 42; 
Wrapper<int> bar = (int)foo; 

या एक संपत्ति के माध्यम से सार्वजनिक रूप से _value बेनकाब।

हालांकि यह एक पुस्तकालय में है, और मैं नहीं चाहता कि उपयोगकर्ता इसे याद रखने पर निर्भर करे, क्या आप लोगों को कोई विचार है कि मैं असाइनमेंट ऑपरेटर को ओवरराइड करने की नकल कैसे कर सकता हूं?

पॉइंटर को बदलने में समस्या (जैसा कि यह किसी अन्य वर्ग को आवंटित करते समय करता है), यह है कि मुझे इन रैपर ऑब्जेक्ट्स के पॉइंटर्स का एक शब्दकोश मिला है, इसलिए मैं उन्हें हर समय बदल नहीं सकता, क्योंकि शब्दकोश तब मिलान करना बंद कर देगा।

अगर यह कुछ हद तक भ्रामक है मैं देख सकता हूँ, इसलिए यदि मैं महत्वपूर्ण कुछ भी, :-)

+0

क्या यह कभी हल किया गया था? मुझे एक ही समस्या है - सिवाय इसके कि मैं बुनियादी प्रकारों को लपेटने के लिए कुछ बना रहा हूं उदा। फ्लोट करें और MyType < float > ए = 1 एफ करने में सक्षम होना चाहते हैं; ए = 2 एफ; एक नया उदाहरण बनाने के बिना ... संदर्भ वास्तव में जादू द्वारा अद्यतन मिलता है? मैं बस कोशिश करता हूं लेकिन मुझे विश्वास नहीं है कि यह एक अच्छा प्रयोग है क्योंकि यदि यह काम करता है तो यह सभी के लिए अंधेरा भाग्य हो सकता है ... – jheriko

उत्तर

1

पूछने के लिए आप Nullable < टी > ... जो एक बहुत करता है पर नज़र डालें तो संकोच न करें छोड़ दिया है आप यहां क्या कर रहे हैं, इसी तरह की चीज, यह एक वैल्यू प्रॉपर्टी का उपयोग करके आंतरिक मूल्य का खुलासा करती है।

बस सूचक को बदलने (जब एक और करने के लिए एक वर्ग के उदाहरण बताए के रूप में यह होता है), कि मैं इन आवरण वस्तुओं की ओर इशारा का एक शब्दकोश मिल गया है है, इसलिए मैं उन्हें हर समय बदल रहा है नहीं हो सकता है में समस्या , क्योंकि शब्दकोश तब मिलान करना बंद कर देगा।

मुझे यकीन नहीं है कि मैं इसका अनुसरण करता हूं, आप वास्तव में शब्दकोश में क्या स्टोर कर रहे हैं? क्योंकि यदि आप संदर्भ संग्रहीत कर रहे हैं, तो सीएलआर उन्हें आवश्यकतानुसार अपडेट करेगा।

+1

जैसा कि मैंने इसे समझा, Nullable को इस तरह के असाइनमेंट को कवर करने के लिए कुछ अतिरिक्त कंपाइलर समर्थन दिया गया था परिदृश्यों। – ajlane

3

आप रैपर < टी > struct बना सकते हैं। हालांकि मुझे यकीन नहीं है कि यह आपके एप्लिकेशन डिज़ाइन के अनुरूप होगा या नहीं।

5

चूंकि असाइनमेंट ऑपरेटर को ओवरलोड नहीं किया जा सकता है, इसलिए कोई वास्तविक अच्छा समाधान नहीं है। जैसा कि किसी और ने बताया है, एक संरचना का उपयोग करके आपको असाइनमेंट सेमेन्टिक्स मिलेंगे जो आपको चाहिए, लेकिन फिर आपको मूल्य अर्थशास्त्र का सामना करना पड़ता है - अक्सर एक अच्छी बात नहीं।

public Wrapper(Wrapper<T> w) 
{ 
    _value = w._value; 
} 

कौन इस वाक्य में परिणाम होगा:

Wrapper<int> foo = 42; 
Wrapper<int> bar = new Wrapper<int>(foo); 

हालांकि अधिक वर्बोज़ से तुम्हारे पास क्या है, यह बेहतर पढ़ता

एक विकल्प निर्माता ओवरलोड है।

या आप, एक Clone विधि (नहीं ICloneable इंटरफेस) जोड़ सकते हैं, ताकि आप लिख सकते हैं:

Wrapper<int> bar = foo.Clone(); 

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

0

यह संपत्ति क्या है। वे आपको परिभाषित करने की अनुमति देते हैं कि असाइनमेंट का क्या अर्थ है। आप इसे कक्षा या संरचना के लिए परिभाषित नहीं कर सकते क्योंकि वे पहले से ही आवश्यक चीजों को करने के लिए भाषा द्वारा परिभाषित हैं। कक्षा में Value संपत्ति जोड़ें।

वैकल्पिक रूप से, अपने डिजाइन का विस्तृत विवरण देने के लिए अपना प्रश्न संपादित करें और यह रैपर इसमें कैसे फिट बैठता है, क्योंकि कोई आसान दृष्टिकोण सुझा सकता है।

0

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

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

यदि मैं सहायक होगा, तो मैं पूरी कक्षा पोस्ट कर सकता हूं, लेकिन यह कुछ हद तक लंबा है (130 लाइनें) या यदि मैं बेहतर होगा तो मैं एक अलग सर्वर पर टॉस कर सकता हूं? (हालांकि यह इस सवाल की अखंडता को दर्द होता है, जैसा कि मैंने यह अंततः है कि सर्वर से हटा सकते हैं)

भी समझा वर्ग वास्तव में मुश्किल है, एक पूरी निबंध लेखन के बिना: -/

वैसे भी मैं करने की कोशिश करेंगे मेरी समस्या का वर्णन करें। CustomerTable और UserTable:

2 टेबल कक्षाएं मान लें

public class CustomerTable 
{ 
    Wrapper<string> Name; 
} 

public class UserTable 
{ 
    Wrapper<string> Name; 
} 
अब

समस्या इस प्रकार है कि कुछ अन्य डेवलपर, उपरोक्त कोड का उपयोग कर सकते है:

CustomerTable customer = new CustomerTable(); 
UserTable user = new UserTable(); 
user.Name = customer.Name; // This breaks my internal dictionary 

क्या डेवलपर किया था चाहिए , इसे काम करने के लिए, था:

user.Name = (string)customer.Name; 

समस्या यह है कि, कोड लिखते समय उनके सही दिमाग में उस बारे में सोचना होगा?

यहां तक ​​कि अगर मैं एक मूल्य संपत्ति का इस्तेमाल किया, डेवलपर अभी भी

user.Name = customer.Name.Value; // or user.Name.Value = .... 

लिखने के लिए याद करने के लिए होगा और फिर डेवलपर इस भूल सकते हैं, और अचानक वह अपवादों या खराब हो जाता है के सभी: डेटा जो डेटाबेस के लिए जारी नहीं है।

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

पुhew बहुत सारे लेखन, और बहुत सारे कोड - अगर मैं लेखन को अधिक करता हूं तो मुझे बताएं।

+2

मैं वैल्यू प्रॉपर्टी का उपयोग करूंगा। एक तरह से एक तरह से कास्टिंग दोनों तरीकों का एक अच्छा विचार कभी नहीं है। डाउन-स्ट्रीम डेवलपर बहुत तेज़ी से सीखेंगे कि आपकी लाइब्रेरी का सही तरीके से उपयोग कैसे करें जब उनके बेवकूफ असाइनमेंट संकलित करने में असफल हो जाते हैं। – ajlane

0

अपने रैपर को दोनों तरीकों से निहित रूप से न डालें।

public class DBValue<T> 
{ 
    public static implicit operator DBValue <T>(T value) 
    { 
     return new DBValue<T>(value); 
    } 

    public static explicit operator T(DBValue <T> dbValue) 
    { 
     return dbValue.Value; 
    } 

    private readonly T _value; 
    public T Value { get { this._value; } } 

    public DBValue(T value) 
    { 
     this._value = value; 
    } 
} 

DBValue<T> से T में कास्ट करना एक हानिपूर्ण रूपांतरण (कम से कम के रूप में, आप तथ्य यह है कि यह डेटाबेस से एक मूल्य है खोना), और से सबसे अच्छा अभ्यास स्पष्ट होना चाहिए। यदि आप DBValue<T> से T पर कास्टिंग करके कुछ खोना नहीं चाहते हैं, तो आप T लौटने वाले गुणों का भी उपयोग कर सकते हैं।

असल में, आप पहले से ही देख चुके हैं कि आपको ऐसा करने की कोशिश क्यों नहीं करनी चाहिए: यदि टीबी और अन्य तरीकों के लिए डीबीवेल्यू को प्रतिस्थापित किया जा सकता है, तो कंपाइलर (या डेवलपर) को किस प्रकार चुनना है?

नीचे धारा डेवलपर्स की आवश्यकता होती है लिखने के लिए:

string value = MyProperty.Value 

या

string value = (string)MyProperty 
बजाय

string value = MyProperty 

... सब महती नहीं है, और है कि यह सुनिश्चित करती है हर कोई जानता है कि क्या हो रहा है।

संपादित करें:

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

+0

मुझे ध्यान रखना चाहिए कि मैंने वास्तव में इस बार दो बार खुद को गलती की है - यह विशेष रूप से मुझे संख्याओं के साथ समस्याएं पैदा करता है: यानी 1 + myValue का प्रकार क्या है यदि myValue एक वर्ग है जो डबल के रूप में रहता है? – ajlane

0

एक जम्मू लेन मैं तुम क्या मतलब है देखते हैं, और मुझे लगता है कि तुम सही हो - मैं सिर्फ पुस्तकालय का उपयोग करने के रूप में संभव के रूप में सरल बनाना चाहते थे।

टी करने के लिए DbValue से निहित कलाकारों के लिए कारण, बस कार्य करता है जो

literalSomething.Text = Server.HtmlEncode((string)SomeTable.SomeStringColumn); 

से उदाहरण के लिए टी

उम्मीद

literalSomething.Text = Server.HtmlEncode(SomeTable.SomeStringColumn); 

बल्कि यह करने के लिए कलाकारों की आवश्यकता है निहित होना

कहा जा रहा है मैं तो बस इस टाइपिंग जबकि अपनी टिप्पणी पढ़ा है, और मुझे लगता है कि काफी मुद्दा है देख सकते हैं।

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

बस DbValue कल्पना:

if (someValue.Value.HasValue) // someValue is DbValue<int?> 

लेकिन फिर इसे फिर से, शायद "बदसूरत" कोड के साथ बेहतर है कोड है जो आप केवल इसे पढ़ने से उम्मीद थी क्या से अलग ढंग से व्यवहार करती है।

मुझे लगता है कि यह प्रश्न वास्तव में "सर्वोत्तम अभ्यास" प्रश्न के रूप में समाप्त होता है।

तो समाप्त करने के लिए, मैं एक मूल्य संपत्ति और उपयोग निहित डाले, और डेवलपर पुस्तकालय उपयोग करने के बजाय सिर्फ इतना है कि साथ रहने के लिए होगा कि पैदा हो जाएगी।:-)

+0

अधिक पठनीय (कम "बदसूरत") कोड के लिए, आप हमेशा int असाइन कर सकते हैं? मूल्य = कुछ वैल्यू। वैल्यू; और फिर उम्मीद के रूप में आगे बढ़ें। – ajlane

0

यह पुराने पोस्ट चित्र अतिरिक्त जानकारी चाहिए आपके इनपुट के लिए

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


यहां तक ​​कि दोनों अपनी अंतर्निहित ऑपरेटरों के साथ मूल दिया Wrapper<T> वर्ग रखते हुए, यहाँ कोड है कि काम करेगा है:

public class CustomerTable 
{ 
    private Wrapper<string> _Name; 
    public Wrapper<string> Name { 
     get { return _Name; } 
     set { _Name = (string)value; } 
    } 
} 

public class UserTable 
{ 
    private Wrapper<string> _Name; 
    public Wrapper<string> Name { 
     get { return _Name; } 
     set { _Name = (string)value; } 
    } 
} 

यह परिवर्तन किया गया है, यह मौजूदा कोड को तोड़ने नहीं होगा, क्योंकि यह अभी भी अनुमति देता है संपत्ति सेट करने के विभिन्न तरीके:

CustomerTable customer = new CustomerTable(); 
UserTable user = new UserTable(); 

user.Name = customer.Name; //*** No longer breaks internal data structures 

user.Name = "string literal"; // Works as expected with implicit cast operator 
user.Name = (string)customer.Name; // Still allowed with explicit/implicit cast operator 
user.Name = customer.Name.Value; // Also works if Value property is still defined 

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

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