2012-04-27 11 views
14

स्थितिवैकल्पिक typedef या सी # में उपवर्गीकरण स्ट्रिंग के लिए

मैं कक्षा कि फ़ाइल पथ के विभिन्न प्रकार के साथ आंतरिक रूप से सौदों है: कुछ स्थानीय, कुछ सुदूर; कुछ रिश्तेदार, कुछ पूर्ण।

यह ऐसा मामला होता था कि इसकी कई विधियां उन्हें string एस के रूप में एक-दूसरे के पास पास करती हैं, लेकिन प्रत्येक विधि की अपेक्षा किस प्रकार की पथ की अपेक्षा रखने के लिए यह बहुत मुश्किल हो गया।

वांछित ठीक

तो हम अनिवार्य रूप से string को typedef चार अलग अलग प्रकार करना चाहता था: RemoteRelative, LocalRelative, RemoteAbsolute, और LocalAbsolute। इस प्रकार स्थिर प्रकार परीक्षक डेवलपर्स को यह सुनिश्चित करने में सहायता कर सकता है कि वे सही अर्थशास्त्र के साथ string एस प्रदान कर रहे हैं और उम्मीद कर रहे हैं।

दुर्भाग्यवश, string बीसीएल में sealed है, इसलिए हम इसे सरल विरासत के साथ नहीं कर सके। और कोई आसान typedef नहीं है, इसलिए हम इसे इस तरह से नहीं कर सके।

वास्तविक ठीक

मैं चार अलग अलग वर्गों सरल है कि प्रत्येक एक readonly string शामिल बना दी।

public struct LocalAbsolutePath { 
    public readonly string path; 
    public LocalAbsolutePath(string path) { 
     this.path = path; 
    } 
} 

जो अधिकतर काम करता है, लेकिन यह अवांछित वर्बोजिटी का थोड़ा सा जोड़ता है।

प्रश्न: क्या मैं स्वाभाविक रूप से सरल सी # वाक्यविन्यास में फिट होने वाले किसी भी विकल्प को देख रहा हूं?

जैसा मैंने ऊपर बताया है, एक सी-शैली typedef string LocalAbsolutePath; या यहां तक ​​कि एक एफ # -स्टाइल type LocalAbsolutePath = string मेरा सपना होगा। लेकिन यहां तक ​​कि कुछ ऐसा कदम है जो कस्टम वर्गों से दिशा बहुत अच्छा होगा।

+0

नहीं है कि यह एक आम पैटर्न से मेल खाते रास्ता खोजने के लिए संभव है:

class CustomerId : LikeType<string> { public CustomerId(string id) : base(id) { } } 

यहाँ कैसे प्रकार व्यवहार करेंगे है? उदाहरण: यदि पथ पूर्ण है, तो इसके सामने कुछ ड्राइव अक्षर होना चाहिए, यदि नहीं, तो यह * नेटवर्क पथ के लिए सापेक्ष होना चाहिए ... – Tigran

+0

@ टिग्रान, बिल्कुल हां, लेकिन यह पहली बार समस्या थी जगह। मैं _compiler_ को यह बताने में सक्षम होना चाहता हूं कि क्या हम सही प्रकार के आसपास गुजर रहे हैं, रनटाइम नहीं। – sblom

+2

असल में मेरा कोड और @ dasblinkenlight एक साथ ले लो और आपके पास एक कक्षा है। :) –

उत्तर

0

मैंने LikeType नामक एक NuGet पैकेज बनाया है जो typedef-सी # कक्षाओं में व्यवहार के समान प्रदान करता है।

इस तरह आप इसका इस्तेमाल होता है:

void ShowTypeBehavior() 
{ 
    var customerId = new CustomerId("cust-001"); // create instance with given backing value 
    string custIdValue = customerId; // implicit cast from class to backing type, sets 'custIdValue' to "cust-001" 

    var otherCustomerId = new CustomerId("cust-002"); 
    var areEqual = customerId == otherCustomerId; // false 
    var areNotEqual = customerId != otherCustomerId; // true 
    var areEqualUsingMethod = customerId.Equals(otherCustomerId); // false 

    var customerIdCopy = new CustomerId("cust-001"); // create separate instance with same backing value 
    var isCopyEqual = customerId == customerIdCopy; // true. Instances are considered equal if their backing values are equal. 
} 
14

आपका समाधान अच्छा है। आप string पर एक प्रकार का रूपांतरण जोड़कर अतिरिक्त वर्बोजिटी से लड़ सकते हैं, जिससे आप LocalAbsolutePath का उपयोग कर सकते हैं जहां कहीं भी string जा सकता है।

public struct LocalAbsolutePath { // Making it a class would be OK too 
    private readonly string path; // <<=== It is now private 
    public LocalAbsolutePath(string path) { 
     this.path = path; 
    } 
    public static implicit operator string(LocalAbsolutePath p) { 
     return p.path; 
    } 
} 
5

क्या आप अपने पथ प्रकार के लिए चार अलग वर्गों बनाने (और यहां तक ​​कि उन्हें एक ही baseclass वारिस है) के अपने वर्तमान दृष्टिकोण रखना है, ताकि आप के लिए तरीकों को सीमित कर सकते करना चाहिए केवल उन चार Path में से एक प्राप्त वस्तुओं।

मुझे लगता है कि var myPath = new LocalAbsolutePath("path") नहीं लग रहा है, जबकि वास्तव में वह सब, var myPath = "path" की तुलना में अधिक वर्बोज़ है के बाद से यह क्या संक्षिप्तता में अभाव है यह मुखरता में के लिए का निर्माण करता है, लेकिन अगर आप वास्तव में चाहते हैं, तो आप अपने वर्ग के बीच निहित कास्टिंग ऑपरेटर लागू कर सकते हैं और स्ट्रिंग, और यह काम किया है:

public static implicit operator LocalAbsolutePath(string path) 
{ 
    return new LocalAbsolutePath(path); 
} 

और अब तुम सिर्फ कर सकते हैं:

LocalAbsolutePath myPath = "Path String"; 
-1

हो सकता है कि मैं यहाँ गलत पेड़ भौंकने हूँ, लेकिन typedef सी में टाइप उपनाम के रूप में कार्यान्वित किया जाता है #, जहाँ तक मुझे पता है। एक प्रकार उपनाम सेट इस के रूप में सरल है:

using LocalAbsolutePath = System.String; 

तो फिर तुम एक मान्य प्रकार के रूप में LocalAbsolutePath उपयोग शुरू कर सकते। इस तरह कम या कम:

LocalAbsolutePath thisPath = "c:\\thisPath"; 

आपकी पोस्ट के आधार पर, मुझे लगता है कि यह वही था जो आप खोज रहे थे। आशा है कि मैं सही हूँ ...!

+0

एक चेतावनी: आप उपनाम उपनाम नहीं कर सकते हैं। इसलिए 'LocalAbsolutePath = string' का उपयोग करके' कथन 'काम नहीं करेगा क्योंकि 'system.String' के लिए' string' वैश्विक प्रकार उपनाम है। इसके अलावा, आपको अच्छा होना चाहिए। – code4life

+0

क्या मैं 4 अलग-अलग नामों के साथ 4 बार कर सकता हूं? और क्या संकलक उन 4 अलग-अलग नामों में से प्रत्येक को अलग-अलग प्रकारों पर विचार करेगा? – sblom

+0

हां, आप कर सकते हैं, संकलक इसे पहचान लेगा। – code4life

0

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

string someStringVar = null; 
MyStringType myStringType = new MyStringType(someStringVar); 
MyStringType myStringTypeNull = null; 
Assert.AreEqual(myStringType, myStringTypeNull); 

एक सार्वजनिक निर्माता के एवज में एक स्थिर पार्स() का उपयोग करना अधिक संतोषजनक था क्योंकि यह मेरे अशक्त वापसी करते हैं। यह गुजरता है:

string someStringVar = null; 
MyStringType myStringType = MyStringType.Parse(someStringVar); 
MyStringType myStringTypeNull = null; 
Assert.AreEqual(myStringType, myStringTypeNull); 

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

अंत में, मैंने सोचा कि यह एक सामान्य के लिए एक आदर्श मामला था जिसे आसानी से पुन: उपयोग किया गया था।

वैसे भी, यहाँ है कि मैं क्या साथ समाप्त हो गया है:

public class StringType<T> where T:class 
{ 
    private readonly string _str; 

    protected StringType(string str) 
    { 
     _str = str; 
    } 

    public static implicit operator string(StringType<T> obj) 
    { 
     return obj == null ? null : obj._str; 
    } 

    public override string ToString() 
    { 
     return _str; 
    } 

    public override int GetHashCode() 
    { 
     return _str.GetHashCode(); 
    } 
} 


public class MyStringType : StringType<MyStringType> 
{ 
    protected MyStringType(string str) : base(str) { } 

    public static MyStringType Parse(object obj) 
    { 
     var str = obj is string ? (string)obj : (obj == null ? null : obj.ToString()); 
     return str == null ? null : new MyStringType(str); 
    } 
} 

टिप्पणियाँ/सुधार/पाठ्यक्रम स्वागत के सरलीकरण!

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