मैं एक सामान्य कंटेनर ऑब्जेक्ट (किया गया; कोई समस्या नहीं) बनाने की कोशिश कर रहा हूं जिसे गहरा क्लोन किया जा सकता है। इसका मतलब है कि इसे अपनी निहित वस्तुओं को गहरा क्लोन करना है, और यही वह है जो मुझे समस्याएं पैदा कर रहा है। यहाँ कुछ कोड है:

    public abstract class VehiclePart {
        public abstract T cloneTypesafe<T>()
                        where T : VehiclePart, new() // L1
    }


    public class Gearstick : VehiclePart { // L2

        public Gearstick() { }

        public override T cloneTypesafe<T>() {
            var res2 = new Gearstick();
            return res2; // L3
            return (T)res2; // L4
        }
    }

यह इस (टिप्पणी L3) को यह कहते हुए खारिज कर देता है कि "एलडीबी.प्रोग्राम.गियरस्टिक' को 'टी' में निहित रूप से परिवर्तित नहीं किया जा सकता है", लेकिन इसका कोई मतलब नहीं है क्योंकि टी स्पष्ट रूप से वाहनपार्ट (लाइन एल 1) से लिया गया है, और गियरस्टिक स्पष्ट रूप से वाहनपार्ट से लिया गया है। (पंक्ति L2), इसलिए रूपांतरण पूरी तरह से कानूनी होना चाहिए।

यहां तक ​​​​कि अगर मेरे पास एक स्पष्ट कलाकार था (लाइन एल 4) यह खुश नहीं है ("एलडीबी। प्रोग्राम। गियरस्टिक' को 'टी' में परिवर्तित नहीं कर सकता"), तो समस्या क्या है और मैं इसे कैसे ठीक करूं? (मैं प्रतिबिंब का उपयोग नहीं करना चाहता, जो समान प्रश्नों के उत्तर में एक सामान्य सुझाव प्रतीत होता है। मैंने ICloneable का उपयोग न करने के लिए कई टिप्पणियां पढ़ी हैं)।

1
user3779002 11 जिंदा 2021, 16:12

4 जवाब

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

तो समस्या क्या है

आपकी विधि का हस्ताक्षर मुझे आपके कोड को निम्नानुसार कॉल करने की अनुमति देता है:

CarWindow myCarWindow = myGearstick.cloneTypesafe<CarWindow>();

यह एक वैध कॉल है, क्योंकि CarWindow, VehiclePart का एक उपप्रकार है। फिर भी, यह स्पष्ट होना चाहिए कि यह कॉल निरर्थक है।


और मैं इसे कैसे ठीक करूं?

C# 9.0 या नए के साथ, आप सहसंयोजक वापसी प्रकारों का उपयोग कर सकते हैं, देखें गुरु स्ट्रॉन का उत्तर

यदि आप पुराने संस्करणों के साथ फंस गए हैं, तो संभावित समाधान के लिए Jamiec's answer देखें। वैकल्पिक रूप से, आप चिंताओं को अलग करने के लिए विधि को अपने IDeepCloneable<T> इंटरफ़ेस में निकाल सकते हैं:

public interface IDeepCloneable<T>
{
    T CloneTypesafe();
}

public class Gearstick : VehiclePart, IDeepCloneable<Gearstick>
{
    public Gearstick CloneTypesafe() { ... }
}

ध्यान दें, जैसा कि जैमीक ने टिप्पणियों में बताया है, टाइप सिस्टम आपको निरर्थक घोषणाएं करने से नहीं रोकेगा, जैसे कि public class Gearstick : VehiclePart, IDeepClonable<Windscreen>

2
Heinzi 11 जिंदा 2021, 17:59

इसके लिए काम करने के लिए (मुझे लगता है) आपने उम्मीद की थी, आपके पास अमूर्त वर्ग पर सामान्य परिभाषा होनी चाहिए

public abstract class VehiclePart<T> where T: new() {
    public abstract T cloneTypesafe();
}

public class Gearstick : VehiclePart<Gearstick> { // L2

    public Gearstick() { }

    public override Gearstick cloneTypesafe() {
        var res2 = new Gearstick();
        return res2; 
    }
}
1
Jamiec 11 जिंदा 2021, 16:19

यह जेनरिक का दुरुपयोग है। यदि आप जेनरिक का उपयोग करते हैं, तो आप कह रहे हैं कि विधि का कॉलर किसी भी प्रकार से गुजर सकता है (कुछ बाधाओं के साथ), और आपकी विधि अभी भी काम करेगी। स्पष्ट रूप से यहाँ ऐसा नहीं है। आपकी cloneTypesafe विधि Gearstick में केवल काम करेगी यदि T Gearstick है। अगर T है, उदा. Engine, या Wheel, तो कास्ट विफल हो जाएगी।

cloneTypesafe को वास्तव में "उस वर्ग के प्रकार" को वापस करना चाहिए, लेकिन हमारे पास सी # में यह कहने का कोई तरीका नहीं है। हालांकि आप इसे एक कामकाज के रूप में कर सकते हैं:

public abstract class VehiclePart<T> 
    where T : VehiclePart<T>, new(){ // implementers are supposed to replace T with their class
    public abstract T cloneTypesafe();
}

// you are not "forced" to say ": VehiclePart<Gearstick>", hence why this is only a workaround
public class Gearstick : VehiclePart<Gearstick> {
    public override Gearstick cloneTypesafe() {
        var res2 = new Gearstick();
        // copy some properties...
        return res2;
    }
}
2
Sweeper 11 जिंदा 2021, 16:26

C#9 के साथ आप यहां जेनरिक की आवश्यकता को हटा सकते हैं और सहसंयोजक वापसी प्रकार:

public abstract class VehiclePart
{
    public abstract VehiclePart cloneTypesafe();
}    

public class Gearstick : VehiclePart {

    public Gearstick() { }

    public override Gearstick cloneTypesafe()
    {
        return new Gearstick(); // your actual implementation
    }
}
3
Guru Stron 11 जिंदा 2021, 16:52