2011-08-07 8 views
14

मैं आदिम .NET मान प्रकारों को अधिक 0 -एस में लपेटकर आदिम .NET मान प्रकारों को अधिक प्रकार-सुरक्षित और अधिक "स्वयं-दस्तावेज़" बनाने के विचार से टकरा रहा हूं। हालांकि, मैं सोच रहा हूं कि वास्तव में वास्तविक दुनिया सॉफ्टवेयर में प्रयास के लायक है या नहीं।कस्टम-स्ट्रक्चर के माध्यम से टाइप-प्रूफिंग आदिम .NET मान प्रकार: क्या यह प्रयास के लायक है?

(यही कारण है कि "प्रयास" नीचे देखा जा सकता है:। एक ही कोड पैटर्न फिर से और फिर लागू करने के लिए होने हम struct रों घोषणा कर रहे हैं और इसलिए विरासत उपयोग नहीं कर सकते कोड पुनरावृत्ति दूर करने के लिए, और अतिभारित ऑपरेटरों के बाद से static घोषित किया जाना चाहिए, वे अलग से प्रत्येक प्रकार के लिए परिभाषित किया जाना है)

इस (वैसे तुच्छ) उदाहरण लें:।

struct Area 
{ 
    public static implicit operator Area(double x) { return new Area(x); } 
    public static implicit operator double(Area area) { return area.x; } 

    private Area(double x) { this.x = x; } 
    private readonly double x; 
} 

struct Length 
{ 
    public static implicit operator Length(double x) { return new Length(x); } 
    public static implicit operator double(Length length) { return length.x; } 

    private Length(double x) { this.x = x; } 
    private readonly double x; 
} 

Area और Length दोनों मूल रूप से double हैं, लेकिन इसे एक विशिष्ट अर्थ के साथ बढ़ाएं। यदि आपने एक विधि परिभाषित की है जैसे & hellip;

Area CalculateAreaOfRectangleWith(Length width, Length height) 

है & hellip; यह सीधे दुर्घटना से एक Area में पारित करने के लिए संभव नहीं होगा। अब तक सब ठीक है।

लेकिन: आप आसानी से एक Areadouble के लिए, या अस्थायी रूप से एक double चर में एक Area भंडारण, और फिर विधि जहां एक Length की उम्मीद है में से गुजर रहा है कि द्वारा कास्टिंग द्वारा इस जाहिरा तौर पर सुधार प्रकार सुरक्षा बस से बचने कर सकते हैं:

Area a = 10.0; 

    double aWithEvilPowers = a; 
    … = CalculateAreaOfRectangleWith((double)a, aWithEvilPowers); 

प्रश्न: यहाँ किसी को भी इस तरह के कस्टम वास्तविक दुनिया में struct प्रकार/उत्पादन सॉफ्टवेयर के व्यापक उपयोग के साथ अनुभव है? यदि ऐसा है तो:

  • कस्टम struct रों में आदिम मूल्य प्रकार के रैपिंग कभी सीधे कम कीड़े में बदल गया है, या अधिक maintainable कोड में, या किसी अन्य प्रमुख लाभ (रों) दिए गए?

  • या कस्टम struct एस के फायदे अभ्यास में उपयोग किए जाने के लिए बहुत छोटे हैं?


पी.एस .: बारे में 5 साल बीत चुके हैं मैं इस सवाल पूछा था। मैं some of my experiences that I've made since then को एक अलग उत्तर के रूप में पोस्ट कर रहा हूं।

+1

** पीएस: ** मुझे पता है कि कोई 'अंतर्निहित' के बजाय 'क्षेत्र -> डबल' कास्ट ऑपरेटर 'स्पष्ट' को परिभाषित करके दो वर्णित सिडस्टेपिंग तकनीकों में से एक से छुटकारा पाने में सक्षम हो सकता है। – stakx

+0

मैं शायद काफी बड़ा नहीं सोच रहा हूं, लेकिन क्या आपने पाया है कि इस तरह की त्रुटि आपके लिए अक्सर आती है? यही है - एक बार जब आपके पास बाहरी स्रोत (संभवतः अनियमित) और आपके प्रोग्राम में आपका डेटा हो, तो यह किसी प्रकार की संरचना में होगा जहां इसे किसी नाम से एक्सेस किया जाता है जो "object.length" जैसा समझ में आता है। आप आमतौर पर कच्चे नंबरों के चारों ओर गुजरने के अंत में नहीं होते हैं, बल्कि आप संरचनाओं के चारों ओर गुजरते हैं। मुझे लगता है कि इस तरह की त्रुटि दुर्लभ है, मैं नहीं सोच सकता कि यह मेरे लिए आ रहा है। –

+0

मुझे संदेह है कि इस प्रकार की त्रुटि मेरे लिए अक्सर नहीं होती है, @ jamietre, लेकिन मुझे उस धारणा का समर्थन करने या अस्वीकार करने के लिए कोई कठोर आंकड़ा नहीं मिला है। हालांकि, अन्य संभावित लाभ भी हैं; आसानी से समझने वाला कोड उनमें से एक हो सकता है। मैं बस इतना स्पष्ट नहीं हूं कि अगर बहुत सारे समान 'संरचना' प्रकारों को लागू करने के लिए उचित ठहरता है ... – stakx

उत्तर

11

मैंने कुछ मिश्रित परिणामों के साथ कुछ साल पहले एक परियोजना में ऐसा किया था।मेरे मामले में, यह विभिन्न प्रकार के आईडी का ट्रैक रखने में बहुत मदद करता था, और जब गलत प्रकार के आईडी का उपयोग किया जा रहा था तो संकलन-समय त्रुटियां होती थीं। और मैं कई अवसरों को याद कर सकता हूं जहां यह वास्तविक बग-इन-द-निर्माण को रोकता है। तो, वह प्लस साइड था। नकारात्मक पक्ष पर, यह अन्य डेवलपर्स के लिए बहुत सहज नहीं था - इस तरह का दृष्टिकोण बहुत आम नहीं है, और मुझे लगता है कि अन्य डेवलपर्स इन सभी नए प्रकारों के साथ उलझन में आ गए हैं। साथ ही, मुझे याद है कि हमें क्रमिकरण के साथ कुछ समस्याएं थीं, लेकिन मुझे विवरण (माफ करना) याद नहीं है।

तो अगर आप ऐसा करना चाहते हैं जा रहे हैं, मैं चीजों की एक जोड़ी की सिफारिश करेंगे:)

1 यकीन है कि आप पहली बार अपने टीम पर अन्य लोगों के साथ बात करते हैं, बताएं कि आपको क्या हासिल करना चाहते हैं इसके और देखें कि क्या आप सभी से "खरीद-इन" प्राप्त कर सकते हैं। अगर लोग मूल्य को नहीं समझते हैं, तो आप "इस अतिरिक्त कोड के बिंदु क्या हैं" की मानसिकता के खिलाफ लगातार लड़ रहे हैं?

2) टी -4 की तरह एक उपकरण का उपयोग कर अपने बॉयलरप्लेट कोड उत्पन्न पर विचार करें। यह कोड का रखरखाव बहुत आसान बना देगा। मेरे मामले में, हमारे पास इन प्रकार के दर्जनों प्रकार थे और कोड-जनरेशन मार्ग पर जाने से परिवर्तन बहुत आसान हो गए और बहुत कम त्रुटि प्रवण हो गई।

यह मेरा अनुभव है। सौभाग्य!

जॉन

+0

एक बहुत ही उचित दृष्टिकोण की तरह लगता है। टी 4 का उपयोग करने के लिए +1 – stakx

+0

+1 - यह हमारे लिए बहुत सारे काम बचाएगा। आईडी और इसी तरह के प्रकार के लिए मुद्रांकन के लिए बढ़िया। और जैसा कि जॉन ने कहा, बग को रोकने में मदद करता है। – Will

3

इस हंगेरी संकेतन के लिए एक तार्किक अगले कदम है, हम एक परियोजना/एपीआई में कुछ इसी तरह जहां esp किया यहाँ योएल से एक उत्कृष्ट लेख http://www.joelonsoftware.com/articles/Wrong.html

देखते हैं। अन्य डेवलपर्स को हमारे कुछ इंटरफेस का उपयोग करने की आवश्यकता थी और इसमें बहुत कम "झूठा अलार्म समर्थन मामलों" थे - क्योंकि यह वास्तव में स्पष्ट था कि क्या अनुमति/आवश्यकता थी ... मुझे संदेह होगा कि इसका मतलब है कि कम से कम कम बग्स हालांकि हमने आंकड़े कभी नहीं किए क्योंकि परिणामस्वरूप ऐप्स हमारे नहीं थे ...

+0

+1, मैंने एक साल पहले उस लेख को पढ़ा है, लेकिन इसे मेरे प्रश्न के संदर्भ में याद नहीं किया होगा। इस तरह से हंगेरियन नोटेशन के बारे में सोचने के लिए दिलचस्प है। धन्यवाद! – stakx

1

मैं अक्सर structs का उपयोग नहीं करता। एक चीज जिसे आप विचार कर सकते हैं वह है कि आपके प्रकार को आयाम की आवश्यकता हो। इस पर विचार करें:

public enum length_dim { meters, inches } 
public enum area_dim { square_meters, square_inches } 
public class Area { 
    public Area(double a,area_dim dim) { this.area=a; this.dim=dim; } 
    public Area(Area a) { this.area = a.area; this.dim = a.dim; } 
    public Area(Length l1, Length l2) 
    { 
     Debug.Assert(l1.Dim == l2.Dim); 
     this.area = l1.Distance * l1.Distance; 
     switch(l1.Dim) { 
      case length_dim.meters: this.dim = square_meters;break; 
      case length_dim.inches: this.dim = square_inches; break; 
     } 
    } 
    private double area; 
    public double Area { get { return this.area; } } 
    private area_dim dim; 
    public area_dim Dim { get { return this.dim; } } 
} 
public class Length { 
    public Length(double dist,length_dim dim) 
    { this.distance = dist; this.dim = dim; } 
    private length_dim dim; 
    public length_dim Dim { get { return this.dim; } } 
    private double distance; 
    public double Distance { get { return this.distance; } } 
} 

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

+1

** 1) ** इकाइयों का ट्रैक रखना निश्चित रूप से कस्टम प्रकार बनाने का एक कारण होगा। ऐसा करने का एक और अधिक सामान्य तरीका होगा: 'वर्ग स्केलर जहां ट्यूनिट: IUnit {सार्वजनिक स्केलर (डबल मान) {...}} ', प्लस एक इकाई प्रकार, उदा। 'वर्ग मीटर: IUnit {...}'; फिर इसे 'नया स्केलर (2.5)' का उपयोग करें। ** 2) ** 'कक्षा' के बजाय मैंने 'struct' का उपयोग करने का कारण यह है कि यह अधिक उचित लगता है। एक नुकसान है: एक हमेशा पैरामीटर-कम c'tor मिलता है। फायदे भी हैं; जैसे VB.NET का 'Is' ऑपरेटर ('object.ReferenceEquals', जो मानों के लिए कोई वास्तविक अर्थ नहीं बनाता है) काम नहीं करेगा। – stakx

0

मैं अपने अनुभव से नहीं कह सकता, अगर यह एक अच्छा विचार है या नहीं। यह निश्चित रूप से यह पेशेवर और विपक्ष है। एक समर्थक यह है कि आपको प्रकार की सुरक्षा की एक अतिरिक्त खुराक मिलती है। कोण के लिए एक डबल को स्वीकार क्यों करें जब आप एक प्रकार को स्वीकार कर सकें जिसमें वास्तविक कोण अर्थशास्त्र (रेडियंस से डिग्री/0 डिग्री, 0 डिग्री सेल्सियस के डिग्री मूल्यों तक सीमित) है। कॉन, आम नहीं है इसलिए कुछ डेवलपर्स को भ्रमित कर सकता है।

कोई वास्तविक वाणिज्यिक उत्पाद कई प्रकार है कि जैसे आप का वर्णन का एक वास्तविक उदाहरण के लिए इस लिंक देखें:

http://geoframework.codeplex.com/

प्रकार कोण, अक्षांश, देशांतर, गति, दूरी शामिल हैं।

2

aprox में। 5 साल बाद मैंने इस सवाल से पूछा है, मैंने अक्सर struct मूल्य प्रकारों को परिभाषित करने के साथ खिलवाड़ किया है, लेकिन शायद ही कभी इसे किया है। कुछ कारण है:

  • यह इतना है कि अपने लाभ के बहुत छोटा है नहीं है, लेकिन एक struct मान प्रकार को परिभाषित करने की लागत बहुत अधिक है।वहाँ शामिल बॉयलरप्लेट कोड के बहुत सारे है:

    • अवहेलना Equals और IEquatable<T> लागू है, और भी GetHashCode ओवरराइड;
    • ऑपरेटरों को लागू करें == और !=;
    • संभावित रूप से IComparable<T> और ऑपरेटर <, <=, > और >= यदि कोई प्रकार ऑर्डर करने का समर्थन करता है;
    • ToString ओवरराइड करें और रूपांतरण विधियों और टाइप-कास्ट ऑपरेटरों को अन्य संबंधित प्रकारों को लागू करें।

    यह केवल दोहराया जाने वाला काम है जो अंतर्निहित आदिम प्रकारों का उपयोग करते समय अक्सर आवश्यक नहीं होता है।

  • अक्सर, कोई उचित डिफ़ॉल्ट मान नहीं है (उदाहरण के लिए ज़िप कोड, दिनांक, समय इत्यादि जैसे मान प्रकारों के लिए)। के बाद से एक डिफ़ॉल्ट निर्माता निषेध नहीं कर सकते हैं, struct जैसे प्रकार को परिभाषित एक बुरा विचार है और उन्हें class के रूप में परिभाषित कुछ क्रम भूमि के ऊपर (आदि जीसी के लिए और अधिक काम करते हैं, अधिक स्मृति अपसंदर्भन,)

  • मैं हेवन 'का अर्थ है टी वास्तव में पाया कि एक अर्थपूर्ण प्रकार को एक अर्थपूर्ण struct में लपेटना वास्तव में प्रकार की सुरक्षा के संबंध में महत्वपूर्ण लाभ प्रदान करता है; IntelliSense/कोड पूर्णता और परिवर्तनीय/पैरामीटर नामों के अच्छे विकल्प विशेष मूल्य प्रकार के समान लाभ प्राप्त कर सकते हैं। दूसरी ओर, जैसा कि एक और उत्तर बताता है, कस्टम डेवलपर्स कुछ डेवलपर्स के लिए अनजान हो सकते हैं, इसलिए उनका उपयोग करने में एक अतिरिक्त संज्ञानात्मक ओवरहेड है।

कुछ उदाहरणों जहां मैं एक struct में एक आदिम प्रकार लपेटकर समाप्त हो गया, आम तौर पर जब वहाँ निश्चित संचालनों उन पर परिभाषित (जैसे इन के बीच में परिवर्तित करने के तरीकों के साथ एक DecimalDegrees और Radians प्रकार) कर रहे हैं किया गया है।

दूसरी तरफ समानता और तुलना विधियों को परिभाषित करने का मतलब यह नहीं है कि मैं एक कस्टम मूल्य प्रकार परिभाषित करता हूं। मैं इसके बजाय आदिम .NET प्रकारों का उपयोग कर सकता हूं और इसके बजाय IEqualityComparer<T> और IComparer<T> के अच्छी तरह से नामित कार्यान्वयन प्रदान कर सकता हूं।

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