9

कौन से टूल्स/पुस्तकालय मौजूद हैं जो एक संरचना ले लेंगे और स्वचालित रूप से एक नए निर्माता बनाने के लिए एक अपरिवर्तनीय रैपर और "बिल्डर" वर्ग भी उत्पन्न करेंगे?अपरिवर्तनीय वर्ग और मिलान करने वाले बिल्डर वर्ग की स्वचालित पीढ़ी

उदाहरण इनपुट:

struct Foo 
{ 
    public int apples; 
    public int oranges; 
    public Foo Clone() {return (Foo) base.MemberwiseClone();} 
} 

उदाहरण आउटपुट:

public class ImmutableFoo // could probably be a struct 
{ 
    private Foo snapshot; 
    internal ImmutableFoo(Foo value) { this.snapshot = value; } 
    public FooBuilder Builder() { return new FooBuilder(snapshot); } 
    public int Apples { get { return snapshot.apples; } } 
    public int Oranges { get { return snapshot.oranges; } } 
} 

public class FooBuilder 
{ 
    private Foo state; 

    public int Apples { get { return state.apples; } set { state.apples = value; } } 
    public int Oranges { get { return state.oranges; } set { state.oranges = value; } } 

    public FooBuilder() { } 

    internal FooBuilder(Foo toCopy) { state = toCopy.Clone(); } 

    public ImmutableFoo Build() 
    { 
     ImmutableFoo result = new ImmutableFoo(state); 
     state = state.Clone(); 
     return result; 
    } 
} 

इस तरह के एक "उपकरण" एक IDE प्लगइन हो सकता है या प्रतिबिंब का उपयोग रन-टाइम में नया वर्ग उत्पन्न कर सकता है।

उदाहरण सी # में है, लेकिन मैं किसी भी स्थिर टाइप OO भाषा (जावा, स्काला, सी ++ आदि)

वांछनीय सुविधाओं के लिए एक समाधान में रुचि होगी:

  • तरीकों पुन: बनाता है बिल्डर कक्षा में struct से
  • पुन: बनाता है अपरिवर्तनीय कक्षा में struct से अविध्वंसक तरीक़ों (esp। Equals() और GetHashCode() और किसी भी इंटरफ़ेस विधि)
  • इसके अलावा एक ०१२३८३१७८८२ उत्पन्न करता हैइंटरफ़ेस में प्रत्येक संरचना सदस्य के लिए केवल-पढ़ने योग्य गुण होते हैं, जो अपरिवर्तनीय और निर्माता दोनों द्वारा कार्यान्वित किए जाते हैं।
  • यदि किसी फ़ील्ड की कक्षा में एक अपरिवर्तनीय समकक्ष है, तो अपरिवर्तनीय वर्ग में अपरिवर्तनीय संस्करण का उपयोग करता है (How do I create a builder in C# for an object that has properties that are referenc types? भी देखें) उदा। List ->ReadOnlyCollection या इसी तरह के।
  • वैकल्पिक रूप से इनपुट के रूप में बिल्डर वर्ग ले (जहां बिल्डर स्वत: गुण के बजाय का उपयोग करता है एक struct को सौंपने की।)
  • Clone विधि की आवश्यकता नहीं है पूर्वनिर्धारित किया जाना

"आप एक उपकरण का उपयोग नहीं करना चाहिए इस तरह ... "जवाब भी स्वागत है।

उत्तर

4

यहां चार संभावित समाधान हैं।

1) सी # या वीबी कोड उत्पन्न करने के लिए CodeDOM का उपयोग करें। यह आपको डिज़ाइनर फ़ाइलों में अपना कोड जेनरेट करने के लिए दृश्य स्टूडियो एक्सटेंशन का उपयोग करने की अनुमति देगा। विज़ुअल स्टूडियो पहले से ऑफ़र किए गए कुछ टूल्स टूल्स के समान - जैसे वेब सेवा कॉल आदि के लिए रैपर जेनरेट करते हैं। दुर्भाग्यवश मुझे विजुअल स्टूडियो को विस्तारित करने के बारे में बहुत कुछ पता नहीं है।

  • पेशेवर - आप इमारत से पहले स्रोत उत्पन्न कर सकते हैं। इससे किसी भी असेंबली से जेनरेट किए गए प्रकारों के खिलाफ कोड लिखना आसान हो जाता है।
  • विपक्ष - भाषा अज्ञेयवादी नहीं। आप समर्थित भाषाओं के साथ अटक गए हैं।

2) Mono.Cecil लाइब्रेरी का उपयोग अपने असेंबली पोस्ट-बिल्ड का विश्लेषण करने के लिए करें। फिर आप नए प्रकार के साथ असेंबली को फिर से लिख सकते हैं।

  • पेशेवर - भाषा अज्ञेयवादी।
  • विपक्ष - यदि आप एक ही असेंबली में प्रकार जोड़ते हैं जिसमें आपके structs परिभाषित किए जाते हैं तो आप उसी असेंबली में जेनरेट किए गए अपरिवर्तनीय संरचना प्रकारों के खिलाफ कोड लिखने में सक्षम नहीं होंगे।यदि आप जेनरेट किए गए प्रकार को एक नई असेंबली में डालते हैं तो यह संभव है।

3) PostSharp का उपयोग करें। मुझे इस पुस्तकालय के बारे में ज्यादा जानकारी नहीं है, इसलिए हो सकता है कि आप अपनी असेंबली में नए प्रकार नहीं जोड़ पाएंगे, लेकिन मुझे पता है कि आप आईएल को तरीकों से इंजेक्ट कर सकते हैं। इसमें बहुत अच्छी चीजें हैं जो गुणों के साथ ऐसा करना आसान बनाती हैं। तो अगर आप ऐसा कर सकता है -

[GenerateImmutable] 
struct Foo 
{ 
    public int apples; 
    public int oranges; 
    public Foo Clone() {return (Foo) base.MemberwiseClone();} 
} 
  • पेशेवरों - भाषा नास्तिक, AOP PostSharp में करने के लिए आसान है।
  • विपक्ष - मोनो सेसिल के समान। और यह भी सुनिश्चित नहीं है कि क्या आप PostSharp का उपयोग करके नए प्रकार उत्पन्न कर सकते हैं।

4) Reflection.Emit पुस्तकालयों में निर्मित अपने अपरिवर्तनीय प्रकारों के साथ एक नई असेंबली उत्पन्न करने के लिए उपयोग करें।

  • पेशेवर - भाषा अज्ञेयवादी, कोई तृतीय पक्ष सामग्री नहीं।
  • विपक्ष - नए असेंबली में जेनरेट किए गए प्रकार डालना चाहिए। उन्हें उसी असेंबली में नहीं जोड़ा जा सकता है जिसमें मूल प्रकार है।
+0

5) अपने कोड का विश्लेषण करने के लिए रोज़लिन का उपयोग करें, और निर्माता को बनाने के लिए टी 4 –

2

बिल्डर के साथ परेशान क्यों?

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

यह मुझे कुछ हद तक परेशान करता है कि आपके पास इस तरह के रैपरों को स्वत: उत्पन्न करने की आवश्यकता महसूस करने के लिए पर्याप्त संख्या में इन structs हैं। मेरे पेट प्रतिक्रिया है कि आप गलत कर रहे हैं ...

अपरिवर्तनीय आवरण का उद्देश्य सिर्फ तब स्नैपशॉट को संग्रहीत करने के लिए बस कुछ इस तरह का उपयोग है, तो यह है:

public struct Snapshot<T> where t : struct 
{ 
    private readonly T data; 
    public Snapshot(T value) { this.data = value; } 
    public T Data { get { return data; } } 
} 

struct में गारंटी है पारित कर दिया फिर कभी नहीं बदला जा सकता है, लेकिन आप सीधे इसके सभी मूल्यों तक पहुंच सकते हैं (और इन परिणामों पर संशोधन अंतर्निहित get_Data फ़ंक्शन को कॉल करते समय बनाई गई प्रतिलिपि पर होते हैं)

+0

संरचना आंतरिक होगी, लेकिन अपरिवर्तनीय वर्ग और निर्माता वर्ग सार्वजनिक होगा। आपकी तकनीक काम करेगी, लेकिन आदर्श समाधान जावा में बराबर होगा (जहां कोई मूल्य प्रकार नहीं है, इसलिए सदस्यवार क्लोन शायद अपरिहार्य है।) – finnw

+0

@finnw संरचना आंतरिक क्यों बनाते हैं? मुझे लगता है कि आपको 'एक स्तर पर जाना' और समझाया जाना चाहिए कि यह मुहावरे क्यों इस्तेमाल किया जाएगा ताकि हम इसे बेहतर ढंग से समझ सकें। यदि आप चीजों को 'स्नैपशॉट करने योग्य' बनाने के लिए डिज़ाइन कर रहे हैं तो बस उन्हें एपीआई फॉर्म के साथ शुरू करने के लिए शुरू करने के लिए तैयार करें foo.X (x) -> foo जहां परिवर्तन हुआ है। तो एक विशिष्ट foo उदाहरण के लिए कोई संदर्भ स्वयं एक पूरी तरह से वैध स्नैपशॉट है। – ShuggyCoUk

+2

@finnw मैं वास्तव में कहूंगा कि, यदि आप ऑटो जेनरेट करने के लिए परेशान हैं तो आप जावा में समान हो सकते हैं क्यों न सिर्फ एक सभ्य अपरिवर्तनीय कार्यान्वयन को स्वचालित करें, जहां प्रत्येक संपत्ति/getFoo केवल पढ़ा जाता है लेकिन एक विहफू (एक्स मान) जो एक नया उदाहरण देता है उस मूल्य के साथ ऑब्जेक्ट का बदला गया है। ऑब्जेक्ट/स्ट्रक्चर का कोई भी उदाहरण अपरिवर्तनीय है, आपके पास चीजों को बदलने के लिए एक अच्छा धाराप्रवाह इंटरफ़ेस है (कुछ कार्यात्मक प्रोग्रामिंग भाषाओं की तरह, इसलिए तर्कसंगत रूप से मानकीकृत)। बिल्डरों या अपरिवर्तनीय संस्करणों की कोई ज़रूरत नहीं, काम पूरा हुआ। – ShuggyCoUk