2010-01-25 10 views
14

Si verificano problemi nell'implementazione di IEnumerable<T> nella classe di raccolta personalizzata in C++/CLI. Ecco la parte rilevante del codice:Implementazione di IEnumerable <T> in C++/CLI

using namespace System::Collections::Generic; 

ref class MyCollection : IEnumerable<MyClass^> 
{ 
public: 
    MyCollection() 
    { 
    } 

    virtual IEnumerator<MyClass^>^ GetEnumerator() 
    { 
     return nullptr; 
    } 
}; 

Quando compilato, questo si traduce nei seguenti errori:

errore C2392: 'System :: Collections :: :: generico IEnumerator ^ MyCollection :: GetEnumerator (void) ': covariante ritorna tipi non sono supportati in tipi gestiti, altrimenti 'sistema :: Collezioni :: IEnumerator ^ System :: Collections :: :: IEnumerable GetEnumerator (void)' sarebbe essere sovrascritto errore C3766: 'MyCollection' deve fornire un implementazione per l'interfaccia metodo 'System :: Collections :: IEnumerator ^ System :: Collections :: IEnumerable :: GetEnumerator (vuoto)'

Questo ha senso, dato che IEnumerable<T> deriva da IEnumerable. Tuttavia, non sono sicuro di come correggere questo errore di compilazione. Se questo è stato C#, avrei implicitamente implementare IEnumerable, però io non sono sicuro di come fare in C++/CLI (se è ancora possibile) in questo modo:

class MyCollection : IEnumerable<MyClass> 
{ 
    public MyCollection() 
    { 
    } 

    public IEnumerator<MyClass> GetEnumerator() 
    { 
     return null; 
    } 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

Se faccio aggiungere un'implementazione di IEnumerable::GetEnumerator(), il compilatore si lamenta di due metodi che differiscono solo per il tipo restituito (che ha anche senso).

Quindi, come si implementa IEnumerable<T> in una classe C++/CLI?

+0

correlati http://stackoverflow.com/questions/3609967/c-cli-is-overloading-on-return-type-only-possible –

risposta

16

È necessario fornire un'implementazione esplicita di the non-generic GetEnumerator() method e includere il namespace non generico:

using namespace System::Collections; 

.... 

virtual IEnumerator^ EnumerableGetEnumerator() = IEnumerable::GetEnumerator 
{ 
    return GetEnumerator<MyClass^>(); 
} 

Aggiornamento: Come accennato nei commenti, la versione esplicita di GetEnumerator deve essere nominato diverso per evitare nome scontro , quindi l'ho chiamato EnumerableGetEnumerator.

Allo stesso modo, in C# si avrebbe dovuto fare in questo modo:

using System.Collections.Generic; 

public class MyCollection : IEnumerable<MyClass> 
{ 
    public MyCollection() 
    { 
    } 

    public IEnumerator<MyClass> GetEnumerator() 
    { 
     return null; 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator<MyClass>(); 
    } 
} 
+0

Proprio attuazione GetEnumerator() non funziona. Se lo faccio, ricevo un errore del compilatore che afferma che le funzioni sovraccaricate non possono differire solo dal tipo restituito. – Andy

+0

Ho aggiornato la mia domanda su come l'avrei implementata in C# – Andy

+0

Indovina che ero un po 'veloce qui ... ORA dovrebbe funzionare. Altrimenti mi sparerò ai piedi. –

11

Non è molto semplice. Ecco la mia pugnalata. Compila gli "spazi vuoti". Uno dei maggiori problemi è l'ambiguità se si utilizzano sia lo spazio dei nomi Raccolte che Collezioni :: Generico. C++/CLI è davvero un dolore.

using namespace System; 
using namespace System::Collections; 

public ref struct Enumerable : public Generic::IEnumerable<String^> { 

public: 
    virtual Generic::IEnumerator<String^>^ GetEnumerator() sealed = Generic::IEnumerable<String^>::GetEnumerator { 
     return gcnew Enumerator(); 
    } 

    virtual IEnumerator^ GetEnumeratorBase() sealed = IEnumerable::GetEnumerator { 
     return GetEnumerator(); 
    } 

private: 
    ref struct TagEnumerator : public Generic::IEnumerator<String^> { 

    public: 
     property String^ Current { 
      virtual String^ get() { 
       throw gcnew NotImplementedException(); 
      } 
     }; 

     property Object^ CurrentBase { 
      virtual Object^ get() sealed = IEnumerator::Current::get { 
       throw gcnew NotImplementedException(); 
      } 
     }; 

     virtual bool MoveNext() { 
      throw gcnew NotImplementedException(); 
     } 

     virtual void Reset() { 
      throw gcnew NotImplementedException(); 
     } 

     virtual ~Enumerator() { 
     } 
    }; 
}; 
+0

Grazie. "Uno dei maggiori problemi è l'ambiguità se si utilizzano sia Collections che Collections :: Generic namespace" <- che, e il fatto che Intellisense (TM) continua a lamentarsi dei ritorni covarianti indipendentemente anche dopo una compilazione riuscita :) – sehe

+0

ci sarà un 'return current' nel getter di' CurrentBase'? – Lars

Problemi correlati