2012-06-21 7 views
11

मेरे पास दो अलग-अलग प्रकार के तार हैं जो मैं चारों ओर गुजर रहा हूं और अपने कोड में उपयोग कर रहा हूं, और दोनों निकट से संबंधित हैं, लेकिन एक दूसरे के लिए भ्रमित नहीं होना चाहिए। मैंने सोचा कि मैं खुद को दो वर्गों के साथ त्रुटियों से बचने में मदद कर सकता हूं, लेकिन अलग-अलग नामों के साथ ताकि विधि हस्ताक्षर (और सामान्य रूप से असंगतता टाइप करें) दो अलग-अलग प्रकार के तारों के अर्थपूर्ण अर्थ को लागू करे। उसी समय, मैं सौ स्थानों में something = "foo"; से something.Value = "foo"; से रिफैक्टर करना नहीं चाहता था।मैं व्युत्पन्न "खोल" कक्षाओं को कैसे घोषित कर सकता हूं जो कुछ भी नहीं बल्कि नाम के रूप में कार्य करता है?

पहले सोचा:

private class FirstKind : string { } 
private class SecondKind : string { } 

विचार किया जा रहा है कि अगर मैं

void MyMethod(FirstKind varOne, SecondKind varTwo) {...} 

है, और फिर MyMethod(secondKindVar, firstKindVar); से कॉल करने की कोशिश करते हैं, मैं एक संकलक त्रुटि मिलती होगी।

वॉल I हिट: string सील कर दिया गया है।

दूसरा विचार: जेनेरिक KindOf<T> कक्षा बनाएं जो कुछ भी नहीं करेगी लेकिन अंतर्निहित रूपांतरण ऑपरेटरों के साथ मूल्य को बाहर निकालेगी। इस तरह:

private class KindOf<T> 
{ 
    public T Value { get; set; } 
    public KindOf() { Value = default(T); } 
    public KindOf(T val) { Value = val; } 
    public static implicit operator T(KindOf<T> kindOf) { return kindOf.Value; } 
    public static implicit operator KindOf<T>(T value) { return new KindOf<T>(value); } 
} 

इस तरह से मैं कुछ इस तरह कर सकता है:

private class FirstKind : KindOf<string> { } 
private class SecondKind : KindOf<string> { } 

दीवार मुझे मारा:, न तो कंस्ट्रक्टर्स और न ही ऑपरेटरों व्युत्पन्न प्रकार में मौजूद है जिसका अर्थ है: KindOf<T> वर्ग से कुछ भी नहीं वारिस करने लगता है मुझे व्युत्पन्न कक्षाओं में अनिवार्य रूप से संपूर्ण आधार वर्ग को फिर से लागू करना होगा। कोड कॉपीिंग। छी।

तो मुझे लगता है कि मुझे यहां कुछ बुनियादी याद आ रही है, और शायद मैं खरपतवार में बंद हूं। मैं जो करने की कोशिश कर रहा हूं उसके लिए कोई विचार?

+1

शायद आप स्पष्ट कर सकते हैं कि "दो अलग-अलग प्रकार के तार" का क्या अर्थ है? –

+1

मेरे सिर के ऊपर से, आपको बस उप-वर्गों पर निहित ऑपरेटरों और रचनाकारों को लागू करने की आवश्यकता हो सकती है। हाँ, कोड कॉपी करने की तरह, लेकिन कम से कम यह संतोषजनक प्रक्रिया को नियोजित नहीं कर रहा है या विरासत का उपयोग नहीं कर रहा है जब विरासत वास्तव में कुछ भी सचमुच संवाद नहीं करता है (अशिष्टता से, "KindOf" क्या है और क्या इसका वास्तव में कुछ मतलब है?) और बस ऐसे वर्गों में कोड डुप्लिकेशंस को कम करने के लिए जिनके समान समान वाक्यविन्यास (लेकिन विभिन्न उपयोग) के अलावा कुछ भी सामान्य नहीं है –

+0

सहमत हैं, कक्षाएं वास्तव में एक ही विरासत पदानुक्रम में नहीं होनी चाहिए, विशेष रूप से आप उनको संदर्भित नहीं करना चाहते हैं एक सामान्य प्रकार से, आप उन्हें अलग रहना चाहते हैं। – Servy

उत्तर

0

मैं सिर्फ तारों के लिए ऐसा करता हूं।

abstract class MyTypedString 
{ 
    protected MyTypedString(string value) 
    { 
    Value = value; 
    } 
    public string Value { get; private set; } 
} 

तो फिर आप अपने FirstKind और SecondKind के साथ इस सार वर्ग को ख़त्म कर सकता है। यह ऑब्जेक्ट को अपरिवर्तनीय बनाएगा जैसे स्ट्रिंग्स हैं। मैं इसे किसी भी निहित रूपांतरण ऑपरेटर नहीं दूंगा।

+0

यह अनिवार्य रूप से उनके दूसरे उदाहरण (केवल कम अच्छा) जैसा ही है। –

0

ऑपरेटरों अभी भी काम करेगा, तो आप सिर्फ अपने kindof वर्ग के .Value सदस्य को संदर्भित करने की जरूरत है:

FirstKind stringFoo = new FirstKind("foo"); 
FirstKind stringQux = new FirstKind("qux"); 

// String concatenation operator 
FirstKind stringTar = new FirstKind(stringFoo.Value + stringQux.Value); 

हालांकि के रूप में आप कहते हैं, नहीं होगा कोई "प्रकार की जाँच" अगर आप दो मिश्रण है, उदा

SecondKind stringBar = new SecondKind("bar"); 
FirstKind stringHal = new FirstKind(stringFoo.Value + stringBar.Value); // this will succeed, even though you intend stringFoo and stringBar to be incompatible 

ऑपरेटरों एक वर्ग का हिस्सा हैं के रूप में 'इंटरफ़ेस तो आप उन्हें फिर से लागू करना चाहिए - लेकिन तुम सिर्फ निहित वर्ग लपेट कर सकते हैं' कार्यान्वयन है, तो आप केवल काम करने के लिए इसे पाने के लिए उबाऊ घुरघुराना काम करने की ज़रूरत है ।

0

आप अपनी कक्षा में implicit रूपांतरण ऑपरेटर को एक स्ट्रिंग पर अधिभारित करने का प्रयास कर सकते हैं। फिर आपको अपने संदर्भों को अपडेट नहीं करना पड़ेगा। वैल्यू। कक्षाओं को अलग रहना होगा और आपको उन लोगों के लिए रचनाकार बनाना होगा जो स्ट्रिंग मान स्वीकार करते हैं। सर्वोत्तम अभ्यास स्ट्रिंग readonly रखना होगा ताकि कक्षा अपरिवर्तनीय हो। स्ट्रिंग क्लास की नकल करना इसका एक प्रतिनिधित्व होना है।

public class FirstKind 
{ 
     private readonly string value; 
     public FirstKind(string v) { this.value = v }; 
     public static implicit operator string(FirstKind v){ return v.value; } 
} 

public class SecondKind 
{ 
     private readonly string value; 
     public SecondKind (string v) { this.value = v }; 
     public static implicit operator string(SecondKind v){ return v.value; } 
} 
+1

वह पहले से ही है ... – Servy

+0

मेरे द्वारा किए जाने से पहले आकस्मिक रूप से पोस्ट किया गया। – Fr33dan

+0

वह पहले से ही ऐसा कर रहा है ... – Servy

0

आप लगभग अपनी जेनेरिक कक्षा का उपयोग कर सकते हैं। स्ट्रिंग (या अन्य प्रकार) से केवल अंतर्निहित कास्टिंग कभी भी काम नहीं कर सकता है, क्योंकि बेस क्लास को यह नहीं पता कि स्ट्रिंग को फर्स्टकिंड या सेकेंडकिंड में डाला जाना चाहिए या नहीं। आधार वर्ग में कास्ट करना अभी भी सामान्य वर्ग के भीतर से किया जा सकता

private class FirstKind : KindOf<string> 
{ 
    public static implicit operator FirstKind(string value) { return new FirstKind{Value = value}; } 
} 
private class SecondKind : KindOf<string> 
{ 
    public static implicit operator SecondKind(string value) { return new SecondKind{Value = value}; } 
} 

:: तो उस भाग की नकल की जानी चाहिए, बाकी तथापि आधार वर्ग में रह सकते हैं

 FirstKind Foo = "Foo"; //via implicit operator in FirstKind 
     string stringFoo = Foo; //via implicit operator in baseclass 
+0

समस्या जो बनी हुई है, यद्यपि यह है कि आप 'Foo.Length' जैसे कुछ नहीं कर सकते हैं। आपको 'Foo.Value.Length' जैसी चीजों को करने के लिए अपने सभी कोड को ठीक करना होगा जो शायद सभी परेशानी के लायक नहीं है। –

+0

हां, जो बदले में KindOfString क्लास के भीतर कॉल करेगा जो कि KindOf से प्राप्त होता है और उन गुणों को लागू करता है, जिनसे अन्य प्रकार के उत्तराधिकारी होते हैं (या यदि केवल स्ट्रिंग का उपयोग किया जाता है, तो जेनेरिक क्लास को पूरी तरह से छोड़ दें)। –

3

ईमानदारी से कहूं तो मैं उस मामले के लिए निहित ऑपरेटरों का उपयोग नहीं करता, या किसी भी विरासत का उपयोग नहीं करता। पूरा विचार एक तरीका है जो FirstKind लेता है। निहित ऑपरेटर के साथ आप बस एक स्ट्रिंग में पास कर सकते हैं और इसे परिवर्तित कर दिया जाएगा; इसका मतलब यह है कि आप कोड को स्पष्ट रूप से यह बताने के लिए मजबूर नहीं कर रहे हैं कि यह पहला/दूसरा प्रकार है। मैं दो वर्गों के साथ रहूंगा कि प्रत्येक के पास सिर्फ एक कन्स्ट्रक्टर होता है जो एक स्ट्रिंग लेता है और केवल पढ़ने की संपत्ति है। आप कुछ और जोड़कर इसे जटिल बना रहे हैं।

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

+0

+1 दुर्भाग्यवश, चूंकि 'स्ट्रिंग' को बंद कर दिया गया है, मुझे डर है कि यह शायद सबसे अच्छा विकल्प है। –

+0

हम इस पर सहमत हैं। "स्ट्रिंग में लागू रूपांतरण" मेरे पीछे विचार था, लेकिन आप सुझाव देते हुए कक्षाओं को अलग रखते हुए भी कर रहे हैं। – Fr33dan

1

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

मेरे सिर के ऊपर से, आपको केवल उप-वर्गों पर निहित ऑपरेटरों और रचनाकारों को लागू करने की आवश्यकता हो सकती है। हाँ, कोड कॉपी करने की तरह, लेकिन कम से कम यह संकलित प्रक्रिया को नियोजित नहीं कर रहा है या विरासत का उपयोग नहीं कर रहा है जब विरासत वास्तव में कुछ भी वास्तविक नहीं है (अशिष्टता से, "KindOf" क्या है और क्या इसका वास्तव में कुछ मतलब है?) और बस कक्षाएं समान वाक्य रचना (लेकिन विभिन्न उपयोगों) के अलावा आम में कुछ भी नहीं है कि भर में कोड दोहराव को कम करने के

public class FirstKind 
{ 
    public string Value { get; private set; } 

    public FirstKind(string value) 
    { 
     this.Value = value; 
    } 

    public static implicit operator FirstKind(string value) 
    { 
     return new FirstKind(value); 
    } 

    public static implicit operator string(FirstKind value) 
    { 
     return value.Value; 
    } 
} 

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

यह बहुत तार नहीं है और भविष्य में परिवर्तनों के लिए आपका कोड खुला है (शायद आप एक नई संपत्ति जोड़ना चाहते हैं? कुछ सत्यापन कोड जोड़ें?) और एपीआई के उपभोक्ताओं को वास्तव में कोई परवाह नहीं है कि कुछ कुछ मामूली कोड डुप्लिकेशन पर सहेजने के लिए है। (शायद आप अपने जीवन थोड़ा आसान बनाने के लिए एक टुकड़ा कर सकते हैं?)

1

अपने प्रश्न में, FirstKind और SecondKind अपने स्ट्रिंग की तरह चर के प्रकार के होते हैं, और string अपने KindOf<T> वर्ग के प्रकार के तर्क है।

public class FirstKind { } 
public class SecondKind { } 

public struct String<TKind> 
{ 
    private readonly string _value; 

    public String(string value) 
    { 
     _value = value; 
    } 

    public override string ToString() 
    { 
     return _value; 
    } 

    public static implicit operator String<TKind>(string s) // see the note below 
    { 
     return new String<TKind>(s); 
    } 

    public static implicit operator string(String<TKind> s) 
    { 
     return s.ToString(); 
    } 

    public static String<TKind> operator +(String<TKind> s1, String<TKind> s2) 
    { 
     return new String<TKind>(s1.ToString() + s2.ToString()); 
    } 

    public int Length 
    { 
     get { return _value.Length; } 
    } 

    // You can add methods like Substring and Trim that delegate to _value. 
} 

: एक अलग दृष्टिकोण (जो कोड अन्य उत्तर के लिए आवश्यक दोहराव से बचा जाता है) FirstKind और SecondKind की भूमिका फ्लिप करने के लिए, उन्हें "मार्कर" वर्गों है कि एक String<TKind> प्रकार के प्रकार के तर्क के रूप में इस्तेमाल कर रहे हैं खाली कर रही है अब आप MyMethod इस तरह की घोषणा कर सकते हैं:

void MyMethod(String<FirstKind> varOne, String<SecondKind> varTwo) 
{ 
    varOne += varOne; // OK 
    varTwo += varTwo; // OK 
    varOne = varTwo; // ERROR 
} 

नोट: मैं एक सादे string से अंतर्निहित रूपांतरण ऑपरेटर में छोड़ दिया है। आप इसे हटाने पर विचार करना चाहेंगे, कोड को स्पष्ट रूप से स्ट्रिंग की तरह पहचानने के लिए मजबूर करना: new String<FirstKind>("...")

+0

एचएम, दिलचस्प दृष्टिकोण। मुझे यह विचार करना होगा। – Atario

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

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