2012-04-15 19 views
5

की घोषणा मेरी समस्या निम्न है। मैंने एक होम प्रोजेक्ट के लिए कोड डिज़ाइन किया है जो स्पष्ट रूप से काम नहीं कर रहा है। हो सकता है कि आप यह पता लगाने में मेरी सहायता कर सकें कि "कोड गंध" कहां से आती है।एक अमूर्त सामान्य प्रकार परिवर्तनीय

ठीक है चलो शुरू करते हैं: मैं कुछ वर्गों को परिभाषित किया है संग्रह प्रकार के विभिन्न चारों ओर तरह रैप करने के लिए:

public abstract class Archive { } 
public class ZipArchive : Archive { } 
public class TarArchive : Archive { } 

उन अभिलेखागार के साथ संभाल करने के लिए, मैं प्रबंधक वर्गों को परिभाषित किया। एक सार एक ही है कि जरूरत व्यवहार को परिभाषित करता,

public abstract class ArchiveManager<T> where T : Archive 
{ 
    public abstract void OpenArchive(T archive); 
} 

और ठोस हैं, जो वास्तव में विशिष्ट behaiour लागू:

public class ZipArchiveManager : ArchiveManager<ZipArchive> 
{ 
    public override void OpenArchive(ZipArchive archive) { /* .. */ } 
} 

public class TarArchiveManager : ArchiveManager<TarArchive> 
{ 
    public override void OpenArchive(TarArchive archive) { /* .. */ } 
} 

क्या अब होता संकलन समय के दौरान, मैं नहीं जानता कि है किस तरह अभिलेखागार मैं कार्रवाई करेंगे की, तो मैं निम्नलिखित की कोशिश की:

class Program 
{ 
    static void Main(string[] args) 
    { 
     ArchiveManager<Archive> archiveManager = null; 

     if (/*some condition*/) {    
      archiveManager = new ZipArchiveManager(); 
     } 
     else { 
      archiveManager = new TarArchiveManager(); 
     } 
    } 
} 

जो निम्न त्रुटि में समाप्त हो गया:

012,

Cannot implicitly convert type 'ZipArchiveManager' to 'ArchiveManager'

जहां तक ​​मैं समझता हूं, सामान्य तर्क को पूरी तरह से परिवर्तित नहीं किया जा सकता है। क्या इस के आसपास आने का कोई तरीका है? क्या यह कोड/डिज़ाइन "गंध" करता है?

अग्रिम में आपका बहुत बहुत धन्यवाद।

+0

एक बनाएं; C# .NET 4.0 के "डायनामिक" कीवर्ड का उपयोग करके एक और तरीका है ...

class Program { static void Main(string[] args) { dynamic archiveManager = null; if (/*some condition*/) { archiveManager = new ZipArchiveManager(); } else { archiveManager = new TarArchiveManager(); } } } 

निर्माण मेरे लिए एक आकर्षण की तरह पाया गैर जेनेरिक बेस क्लास, या एक कॉन्वर्स इंटरफ़ेस का उपयोग करें। – CodesInChaos

+1

इसके अलावा, 'ओपनआर्किव' का हस्ताक्षर मुझे गलत लगता है। क्या इसे स्ट्रीम प्राप्त नहीं होनी चाहिए, और 'टी' वापस करनी चाहिए? – CodesInChaos

उत्तर

2

आप एक अमूर्त वर्ग के बजाय एक contravariant इंटरफ़ेस का उपयोग कर सकते हैं जो किसी भी कार्यक्षमता को लागू नहीं करता है।

public interface IArchiveManager<out T> 
    where T : Archive 
{ 
    T OpenArchive(Stream stream); 
} 

फिर, बस अपने प्रबंधक कक्षाओं में इंटरफ़ेस को लागू:

public class ZipArchiveManager : IArchiveManager<ZipArchive> 
{ 
    public ZipArchive OpenArchive(Stream stream) 
    { 
     // ... 
    } 
} 

public class TarArchiveManager : IArchiveManager<TarArchive> 
{ 
    public TarArchive OpenArchive(Stream stream) 
    { 
     // ... 
    } 
} 
+0

आपके उत्तरों के लिए धन्यवाद। Contravariant इंटरफ़ेस इस पर काबू पाने का एकमात्र तरीका प्रतीत होता है। हालांकि मुझे विश्वास है कि मुझे पूरी तरह से अपने वास्तुकला को फिर से सोचना है ... :( – Flagg1980

0

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

+0

'गतिशील' का उपयोग करने का नकारात्मक पक्ष यह है कि आप स्थैतिक प्रकार की जांच खो देते हैं। यदि आपने कभी भी अपना विधि नाम, विधि हस्ताक्षर या रचनाकारों को बदलने का निर्णय लिया है, कंपाइलर इसे 'गतिशील' प्रकारों के लिए नहीं पकड़ पाएगा। – Michael

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