2010-01-25 12 views
14

Ich habe Probleme bei der Implementierung IEnumerable<T> in meiner benutzerdefinierten Sammlung Klasse in C++/CLI. Hier ist der relevante Teil des Codes:IEnumerable implementieren <T> in C++/CLI

using namespace System::Collections::Generic; 

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

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

Wenn kompiliert, führt dies in der folgenden Fehler:

Fehler C2392: ‚System :: Sammlungen :: Allgemeine :: IEnumerator ^ MyCollection :: GetEnumerator (void) ': covariant gibt Typen sind nicht in verwalteten Typen unterstützt, sonst 'System :: Sammlungen :: IEnumerator ^ System :: Sammlungen :: IEnumerable :: GetEnumerator (void)' außer Kraft gesetzt werden würde Fehler C3766: 'MyCollection' muss eine Implementierung für die Schnittstelle bieten Methode 'System :: Sammlungen :: IEnumerator ^ System :: Sammlungen :: IEnumerable :: GetEnumerator (void)'

Dies macht Sinn, da IEnumerable<T> stammt von IEnumerable. Ich bin mir jedoch nicht sicher, wie ich diesen Kompilierfehler beheben kann. Wenn diese C#, würde ich implizit IEnumerable implementieren, aber ich bin nicht sicher, wie das in C zu tun ++/CLI (wenn das überhaupt möglich ist) wie folgt aus:

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

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

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

Wenn ich eine Implementierung von IEnumerable::GetEnumerator() tun hinzuzufügen, der Compiler beklagt sich über zwei Methoden, die sich nur nach Rückgabetyp unterscheiden (was auch Sinn macht).

Also, wie implementiere ich IEnumerable<T> in einer C++/CLI-Klasse?

+0

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

Antwort

16

Sie müssen eine explizite Implementierung von the non-generic GetEnumerator() method bieten und auch die nicht-generischen Namensraum:

using namespace System::Collections; 

.... 

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

Update: Wie in den Kommentaren erwähnt, muss die explizite Version von GetEnumerator unterschiedlich benannt werden Namenskonflikt zu vermeiden , also habe ich es EnumerableGetEnumerator genannt.

in C# In ähnlicher Weise würden Sie es wie folgt tun:

using System.Collections.Generic; 

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

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

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

Gerade Umsetzung GetEnumerator() funktioniert nicht. Wenn ich das tue, erhalte ich einen Compilerfehler, der besagt, dass überladene Funktionen sich nicht nur vom Rückgabetyp unterscheiden können. – Andy

+0

Aktualisiert meine Frage mit, wie ich es in C# implementieren würde – Andy

+0

Ich denke, ich war ein bisschen schnell hier ... Jetzt sollte es funktionieren. Wenn nicht, werde ich mich in den Fuß schießen. –

11

Es ist nicht sehr einfach ist. Hier ist mein Stich. Fülle die Lücken aus". Eines der größten Probleme ist die Mehrdeutigkeit, wenn Sie sowohl Collections als auch Collections :: Generic namespace verwenden. C++/CLI ist wirklich ein Schmerz.

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

Danke. "Eines der größten Probleme ist die Mehrdeutigkeit, wenn Sie sowohl Collections als auch Collections :: Generic namespace" verwenden - und dass sich Intellisense (TM) immer wieder über kovariante Ergebnisse beschwert, selbst nach einer erfolgreichen Kompilierung :) – sehe

+0

Sollte nicht gibt es einen 'return Current' im Getter von' CurrentBase'? – Lars

Verwandte Themen