मैं एक ऐसा एप्लिकेशन लिख रहा हूं जो उपयोगकर्ता को परीक्षण चलाने की अनुमति देता है। एक परीक्षण में कई अलग-अलग ऑब्जेक्ट होते हैं, जैसे कि कॉन्फ़िगरेशन, तापमान और बेंचमार्क। सेटिंग्स और इसी तरह एक्सएमएल के बीच आगे और पीछे सहेजे जाते हैं। मैं अपने कोड में अलग-अलग XElements पास करता हूं ताकि मैं अलग-अलग परिस्थितियों के लिए अंतिम xml दस्तावेज़ को अलग-अलग बना सकूं। मैं कुछ ऐसा करना चाहता हूं:

public abstract class BaseClass<T>
{
    abstract static XElement Save(List<T>);
    abstract static List<T> Load(XElement structure);
}

public class Configuration : BaseClass<Configuration>
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    //etc...

    public static XElement Save(List<Configuration>)
    {
        XElement xRoot = new XElement("Root");
        //etc...
        return xRoot;
    }

    public static List<Configuration> Load(XElement structure)
    {
        List<BaseClass> list = new List<BaseClass>();
        //etc...
        return list;
    }
}

public class Temperature : BaseClass<Temperature>
{
    public float Value { get; set; }

    public static XElement Save(List<Temperature>)
    {
        //save
    }

    public static List<Temperature> Load(XElement structure)
    {
        //load
    }
}

[संपादित करें]: संशोधित प्रश्न (उपरोक्त कार्यों के बदले हुए हस्ताक्षर)[/संपादित करें]

बेशक, मुझे वास्तव में बेसक्लास के स्थिर तरीकों को ओवरराइड करने की अनुमति नहीं है। इस तक पहुंचने का सबसे अच्छा तरीका क्या है? मैं चाहता हूं कि निम्नलिखित में से जितना संभव हो उतना मान्य हो:

List<Temperature> mTemps = Temperature.Load(element);
List<Configuration> mConfigs = Configuration.Load(element);

Temperature.Save(mTemps);
Configuration.Save(mConfigs);

[संपादित करें]उपरोक्त इच्छित उपयोग कोड परिवर्तित[/संपादित करें]

एकमात्र समाधान जिसके बारे में मैं सोच सकता हूं वह निम्नलिखित है, जो स्वीकार्य नहीं है:

public class File
{
    public static XElement Save(List<Temperature> temps)
    {
        //save temp.Value
    }

    public static XElement Save(List<Configuration> configs)
    {
        //save config.Property1
        //save config.Property2
    }

    //etc...
}
3
AGuyInAPlace 5 अगस्त 2011, 00:32
1
विधियां स्थिर क्यों होनी चाहिए?
 – 
BoltClock♦
5 अगस्त 2011, 00:34
मैं कॉन्फ़िगरेशन का उदाहरण बनाए बिना कॉन्फ़िगरेशन की एक सूची सहेजने में सक्षम होना चाहता हूं। हालांकि यह संभव है, ऐसा नहीं लगता कि यह आवश्यक होना चाहिए।
 – 
AGuyInAPlace
5 अगस्त 2011, 00:37

3 जवाब

सबसे बढ़िया उत्तर

स्टेटिक विधियां कक्षा के उदाहरण का हिस्सा नहीं हैं। इसलिए उन्हें ओवरराइड करने का वैसे भी कोई मतलब नहीं है। वे उस इंस्टेंस के किसी भी गैर-स्थिर भाग तक नहीं पहुंच सकते, जिसके वे सदस्य होते हैं।

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

(फिर से संपादित करें)

मेरे मूल सुझाव के समान ही इस पर एक और दरार है। मैंने वास्तव में इसका परीक्षण किया और यह काम करता है, इसलिए मुझे लगता है कि यह सबसे अच्छा है जो आप सभी कार्यक्षमता प्राप्त करने के लिए कर सकते हैं (परीक्षण प्रकारों और सशर्त रूप से कॉलिंग कोड के अलावा)। आपको अभी भी Load के लिए एक प्रकार पास करने की आवश्यकता है, अन्यथा, रनटाइम को पता नहीं होगा कि किस प्रकार की वापसी की उम्मीद है। लेकिन Save सार्वभौमिक रूप से काम करता है। और उपवर्ग कार्यान्वयन दृढ़ता से टाइप किए जाते हैं।

यह सूची में पहली वस्तु को इसके प्रोटोटाइप के रूप में उपयोग करता है, काफी सरल है।

public interface IBaseObject 
{
    XmlElement Save(IEnumerable<IBaseObject> list);
    IEnumerable<IBaseObject> Load(XmlElement element);
}
public interface IBaseObject<T> where T: IBaseObject 
{
    XmlElement Save(IEnumerable<T> list);
    IEnumerable<T> Load(XmlElement element);
}

public class Temperature : IBaseObject<Temperature>, IBaseObject 
{

    public XmlElement Save(IEnumerable<Temperature> list)
    {
        throw new NotImplementedException("Save in Temperature was called");
    }

    public IEnumerable<Temperature> Load(XmlElement element)
    {
        throw new NotImplementedException("Load in Temperature was called");
    }

    // must implement the nongeneric interface explicitly as well

    XmlElement IBaseObject.Save(IEnumerable<IBaseObject> list)
    {
        return Save((IEnumerable<Temperature>)list);
    }

    IEnumerable<IBaseObject> IBaseObject.Load(XmlElement element)
    {
        return Load(element);
    }
}

// or whatever class you want your static methods living in

public class BaseObjectFile
{
    public static XmlElement Save(IEnumerable<IBaseObject> list)
    {
        IBaseObject obj = list.DefaultIfEmpty(null).First();  // linq
        return obj==null ? null : obj.Save(list);
    }
    public static IEnumerable<IBaseObject> Load<T>(XmlElement element) 
        where T: IBaseObject, new()
    {
        IBaseObject proto = new T();
        return proto.Load(element);
    }
}

(मूल संपादन)

इसमें एक समस्या है कि आपको स्थिर विधियों को एक प्रकार से कॉल करना होगा, उदा।

BaseClass<Temperature>.Load()

सहेजें विधि के लिए इसके चारों ओर एक रास्ता है, लेकिन आप जो चाहते हैं उसका हिस्सा संभव नहीं है। लोड विधि यह नहीं जान सकती कि किस प्रकार की सूची वापस करनी है क्योंकि इसके एकमात्र पैरामीटर में रिटर्न प्रकार के बारे में कोई जानकारी नहीं है। इसलिए, यह संभवतः तय नहीं कर सकता कि किस प्रकार को प्रोटोटाइप के रूप में बनाया जाए। तो कोई बात नहीं, यदि आप सामान्य लोड विधि का उपयोग करना चाहते हैं, तो आपको इसे उपरोक्त सिंटैक्स की तरह एक प्रकार से पास करना होगा।

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

अंततः, हालांकि, मुझे लगता है कि ऐसा कुछ करना बहुत आसान होगा:

public static XElement Save(List<IBaseClass> list)
{       
    if (list is Temperature) {
       // do temperature code
    } else if (list is SomethingElse) {
      // do something else
    } 
}

वैसे भी - जैसे मैंने कहा कि इस तरह से सेव विधि को भी काम करने के लिए प्रतिबिंब की आवश्यकता होगी। मैं बस सरल दृष्टिकोण का उपयोग करूंगा।

(मूल खराब कोड हटा दिया गया)

4
Jamie Treworgy 5 अगस्त 2011, 04:14
साथ ही, प्रासंगिक नहीं है लेकिन क्या अंडरस्कोर '_' से शुरू होने वाले विधि नामों का कोई महत्व है? सी ++, जावा, आदि जैसी अन्य भाषाओं में भी? यह कुछ ऐसा है जिसे मैं समय-समय पर देखता हूं और उत्सुक हूं कि ऐसा क्यों किया जाता है।
 – 
AGuyInAPlace
5 अगस्त 2011, 01:37
इस तरह, आप BaseClass.Save(data) नहीं कर सकते, आपको data का ठोस प्रकार निर्दिष्ट करना होगा, जो कि ओपी बचने की कोशिश कर रहा था। आप टाइप अनुमान का उपयोग करके इसे ठीक कर सकते हैं, लेकिन इसके लिए सूचियों की आवश्यकता होगी उदा। List<Temperature>, जो कि ऐसा प्रतीत नहीं होता है।
 – 
svick
5 अगस्त 2011, 01:54
यह कभी-कभी आंतरिक उपयोग के लिए उपयोग की जाने वाली विधि के लिए उपयोग किया जाने वाला एक सम्मेलन है। वहां हमें वास्तव में इसके साथ एक समस्या है - आप जो चाहते हैं उसका हिस्सा वास्तव में संभव नहीं है, मैं उत्तर को अपडेट करने वाला हूं।
 – 
Jamie Treworgy
5 अगस्त 2011, 01:54
यह काफी काम नहीं करता है, क्योंकि मुझे एक सूची वापस करने की आवश्यकता होती है, जब मुझे एक सूची <तापमान> वापस करने की आवश्यकता होती है। अन्यथा, मैं तापमान के लिए विशिष्ट अन्य गुणों और विधियों तक नहीं पहुंच सकता। सूची लोड () के बजाय सूची <तापमान> लोड () का उपयोग करने का कोई तरीका है?
 – 
AGuyInAPlace
5 अगस्त 2011, 01:55
1
List<IBaseClass>, List<Temperature> के साथ सहसंयोजक है। आप एक व्युत्पन्न ऑब्जेक्ट मॉडल बना सकते हैं जो प्रत्येक उपवर्ग को एक जोरदार टाइप की गई सूची को वापस करने की अनुमति देता है, लेकिन आपका लक्ष्य एक एकीकृत विधि को कॉल करना है चाहे कोई भी वस्तु प्रकार हो। इसलिए इसे आधार प्रकार की सूची वापस करनी चाहिए। आपके पास यह दोनों तरह से नहीं हो सकता। यदि आप किसी वस्तु को उसके कम से कम व्युत्पन्न प्रकार के रूप में मान रहे हैं, तो आप केवल सामान्य विधियों तक ही पहुँच सकते हैं।
 – 
Jamie Treworgy
5 अगस्त 2011, 02:07

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

string SerialiseToString<T>(T source)
{
    using (StringWriter sw = new StringWriter() && XmlSerializer xml = new XmlSerializer(typeof(OrderedItem)))
    {
        xml.Serializer(sw, source);
        return sw.ToString();
    }
}

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

1
foxy 5 अगस्त 2011, 00:54
मुझे डर है कि मैं वर्तमान में किस प्रकार के बेसक्लास के साथ काम कर रहा हूं, इसके आधार पर सेव () और लोड () कार्यों के लिए एक अनूठा कार्यान्वयन है। प्रत्येक प्रकार के लिए अद्वितीय अतिरिक्त जानकारी है जिसे एक्सएमएल से भेजा/पार्स किया जाना चाहिए।
 – 
AGuyInAPlace
5 अगस्त 2011, 02:24

यदि साझा भाग समान है, तो आप इसे BaseClass में डाल सकते हैं:

public static XElement Save(IEnumerable<BaseClass> list)
{
    var root = new XElement("root");
    foreach (var item in list)
    {
        item.Save(root);
    }
    return root;
}

यहाँ, Save(XElement) एक आभासी विधि है, प्रत्येक प्रकार इसे लागू करता है।

जाहिर है, आप इसे लोडिंग के साथ नहीं कर सकते हैं, आपको या तो यह जानना होगा कि आप किस प्रकार लोड कर रहे हैं, या यह पता लगाने का कोई तरीका है कि आप किस प्रकार लोड कर रहे हैं।

1
svick 5 अगस्त 2011, 01:50
प्रश्न उन तरीकों के बारे में है जो वस्तुओं की सूचियों से निपटते हैं। मेरी धारणा यह थी कि प्रत्येक तत्व को सहेजने के बजाय विभिन्न कार्यान्वयनों को सूची के साथ और अधिक करने की आवश्यकता होगी। अन्यथा प्रश्न छोटा है, और इस तरह की स्थिर विधि को पहले स्थान पर रखने में बहुत कम उद्देश्य होगा।
 – 
Jamie Treworgy
5 अगस्त 2011, 02:15
सही। पूरी सूची से जानकारी एकत्र की जाती है, उदाहरण के लिए उच्चतम और निम्नतम तापमान, या बेंचमार्क की सूची को चलाने के लिए अपेक्षित समय। यह जानकारी विशिष्ट है, जिसका अर्थ है कि प्रत्येक व्युत्पन्न वर्ग को सेव () और लोड () के एक अद्वितीय कार्यान्वयन की आवश्यकता होती है
 – 
AGuyInAPlace
5 अगस्त 2011, 02:22