2012-04-27 24 views
6

से कनवर्ट नहीं किया जा सकता है मुझे सूची <> पर जेनेरिक ऑब्जेक्ट जोड़ने का प्रयास करते समय त्रुटि हो रही है।सामान्य प्रकार से इंटरफ़ेस

शायद यह कोविरिएंस और कंट्रावाइरिएंस से संबंधित है लेकिन मुझे यकीन नहीं है कि इस के आसपास कैसे काम करना है। मैंने का उपयोग करके अपने सामान्य प्रकारों को प्रतिबंधित करने का प्रयास किया है जहां टी: आईआरजीस्टर

मेरे पास एक रजिस्टर का प्रतिनिधित्व करने के लिए एक इंटरफेस है और फिर दो वर्ग जो बाइट रजिस्ट्रार और डबलवॉर्ड रजिस्ट्रार का प्रतिनिधित्व करते हैं।

public interface IRegister 
{ 
    string Name {get;set;} 
} 

public class ByteRegister : IRegister 
{ 
... 
} 

public class DoubleWordRegister : IRegister 
{ 
... 
} 

मेरे पास एक और वर्ग है जो इन रजिस्टरों के एक ब्लॉक को उसी प्रकार का प्रतिनिधित्व करता है।

public class RegisterBlock<T> where T:IRegister 
{ 
    private IList<T> _registers; 

... constructors, properties etc 

    public void AddRegister(T register) 
    { 
     _registers.Add(register); 
    } 
} 

और अंत में मैं एक RegisterMap वर्ग जो रजिस्टर ब्लॉक की सूची और ब्लॉक के भीतर प्रत्येक रजिस्टर परिभाषित करने के लिए प्रयोग किया जाता है है।

public class RegisterMap 
{ 
    private List<RegisterBlock<IRegister>> _blocks; 

    public RegisterMap() 
    { 
     _blocks = new List<RegisterBlock<IRegister>>(); 

     RegisterBlock<ByteRegister> block1= new RegisterBlock<ByteRegister>("Block1", 0); 
     block1.AddRegister(new ByteRegister("Reg1")); 
     block1.AddRegister(new ByteRegister("Reg2")); 
     _blocks.Add(block1); 

     RegisterBlock<DoubleWordRegister> block2= new RegisterBlock<DoubleWordRegister>("Block2", 10); 
     block2.AddRegister(new DoubleWordRegister("Reg3")); 
     block2.AddRegister(new DoubleWordRegister("Reg4")); 
     block2.AddRegister(new DoubleWordRegister("Reg5")); 
     _blocks.Add(block2); 
    } 
} 

हालांकि मैं निम्न त्रुटि हो रही है: लाइन पर

Error 20 Argument '1': cannot convert from 'RegisterBlock<ByteRegister>' to 'RegisterBlock<IRegister>' _blocks.Add (block1) और इसी तरह _blocks.Add पर (block2);

+1

आपका प्रश्न क्या है? कंपाइलर त्रुटि बहुत स्पष्ट है। – phoog

उत्तर

5

यह वास्तव में **variance problem है। आप अपने RegisterBlock वर्ग के लिए एक और इंटरफेस की आवश्यकता होगी, शायद IRegisterBlock:

public class RegisterBlock<T> : IRegisterBlock 
    where T : IRegister 

तो फिर तुम IRegisterBlock की एक सूची बना सकते हैं:

private List<IRegisterBlock> _blocks; 

मैं वास्तव में पिछले सप्ताह हमारे कोड आधार में एक ऐसी ही स्थिति थी, और यह ठीक है कि मैंने इसे कैसे हल किया।

+0

वाह .. मैं आज से पहले ** भिन्नता समस्या में कभी नहीं जानता/भाग गया। मैं आमतौर पर IENumerable का उपयोग नहीं करता .. लेकिन अब मुझे पता है कि इसका उपयोग कब किया जाए। धन्यवाद .. मुझे लगता है कि मैंने आज कुछ सचमुच महत्वपूर्ण कुछ सीखा! मेरी विधि एक सूची की अपेक्षा कर रही थी जहां सूची contravariant है, इसलिए IEnumarable का उपयोग कर सही अर्थ +1 बनाता है – ppumkin

2

केवल इंटरफेस सी # में कॉन्वर्सेंट या contravariant हो सकता है, तो आपपर अपने RegisterBlock<> कॉन्वेंरिएंट को स्पष्ट रूप से चिह्नित नहीं कर सकते हैं।

RegisterBlock<IRegister> block1= new RegisterBlock<IRegister> 

ByteRegister और DoubleWordRegister दोनों के बाद से IRegister लागू आप उनमें से या तो जोड़ सकते हैं:

हालांकि, अगर आप वास्तव में नहीं सहप्रसरण इस मामले में, तुम बस के रूप में अपने दो संग्रह वस्तुओं की घोषणा करने की जरूरत है जरूरत RegisterBlock<IRegister>

12

मुझे लगता है कि आप एक प्रश्न पूछने के लिए भूल गए। आपने केवल तथ्यों का एक गुच्छा बताया है। मैं आपका प्रश्न मानने जा रहा हूं "संकलक इस त्रुटि का उत्पादन क्यों करता है?"

संकलक उस त्रुटि का उत्पादन करता है क्योंकि उस त्रुटि को उत्पन्न करने के लिए रनटाइम पर क्रैश हो जाएगा। मान लीजिए कि हमने अनुमति दी:

List<RegisterBlock<IRegister> _blocks = new List<RegisterBlock<IRegister>>(); 
RegisterBlock<ByteRegister> block1= new RegisterBlock<ByteRegister>(); 
_blocks.Add(block1); // Illegal, but suppose it was legal. 

अब यह क्या रोकता है?

RegisterBlock<IRegister> block1Again = _blocks[0]; 

कुछ भी नहीं।_blocksRegisterBlock<IRegister> की एक सूची है, इसलिए निश्चित रूप से _blocks[0]RegisterBlock<IRegister> प्रकार का है। लेकिन याद रखें कि निश्चित रूप से सूची में पहला आइटम वास्तव में RegisterBlock<ByteRegister> है।

अब यह क्या रोकता है?

block1Again.AddRegister(new DoubleWordRegister())? 

कुछ भी नहीं। block1Again प्रकार RegisterBlock<IRegister> है, जिसमें एक विधि AddRegister(IRegister) है, और DoubleWordRegisterIRegister लागू करता है।

तो आप केवल एक ब्लॉक में एक डबल शब्द रजिस्टर डालते हैं जिसमें केवल बाइट रजिस्ट्रार हो सकते हैं।

स्पष्ट रूप से यह सुरक्षित नहीं है। एकमात्र ऐसा स्थान जहां संकलन समय पर अवैध बनाया जा सकता है, पहले चरण में है; कॉन्वेंटर रूपांतरण पहले स्थान पर कानूनी नहीं है।

संयोग से, आपका प्रश्न अक्सर दिन में कई बार पूछा जाता है। दो बार अब तक आज सुबह:

Implementing nested generic Interfaces

0

हो सकता है कि अगर आप की तरह कुछ किया।

ByteRegisterBlock : RegisterBlock<ByteRegister> 

यह आपके कोड को काम करना चाहिए, हालांकि, आप कुछ लचीलापन खो देते हैं।

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