2010-01-25 19 views
14

Tengo problemas para implementar IEnumerable<T> en mi clase de colección personalizada en C++/CLI. Aquí está la parte correspondiente del código:Implementación de IEnumerable <T> en C++/CLI

using namespace System::Collections::Generic; 

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

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

Cuando compilado, esto se traduce en los siguientes errores:

error c2392: 'del sistema :: Colecciones :: :: Genérico IEnumerator ^ MiColeccion :: GetEnumerator (void) ': covariante vuelve tipos no son apoyado en tipos administrados, de lo contrario 'del sistema :: Colecciones :: IEnumerator ^ Sistema :: Colecciones :: :: IEnumerable GetEnumerator (void)' se aplicaría, error C3766: 'MiColeccion' debe proporcionar una implementación de la interfaz método 'del sistema :: Colecciones :: IEnumerator ^ Sistema :: Colecciones :: :: IEnumerable GetEnumerator (void)'

Esto tiene sentido, ya IEnumerable<T> deriva de IEnumerable. Sin embargo, no estoy seguro de cómo solucionar este error de compilación. Si se trataba de C#, me implícitamente implemento IEnumerable, sin embargo no estoy seguro de cómo hacerlo en C++/CLI (si eso es posible) así:

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

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

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

Si hago añadir una implementación de IEnumerable::GetEnumerator(), el compilador se queja de dos métodos que difieren solo por el tipo de devolución (que también tiene sentido).

Entonces, ¿cómo implemento IEnumerable<T> en una clase de C++/CLI?

+0

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

Respuesta

16

Debe proporcionar una implementación explícita de the non-generic GetEnumerator() method e incluir el espacio de nombres no genérico:

using namespace System::Collections; 

.... 

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

Actualización: Como se mencionó en los comentarios, la versión explícita de GetEnumerator debe llamarse diferente para evitar conflicto de nombres , así lo he llamado EnumerableGetEnumerator.

Del mismo modo, en C# que tendría que hacerlo de esta manera:

using System.Collections.Generic; 

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

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

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

Sólo implementación GetEnumerator() no funciona. Si lo hago, aparece un error del compilador que indica que las funciones sobrecargadas no pueden diferir solo por el tipo de devolución. – Andy

+0

Actualicé mi pregunta sobre cómo implementarla en C# – Andy

+0

Supongo que fui un poco rápido aquí ... AHORA debería funcionar. Si no, me dispararé en el pie. –

11

No es muy sencillo. Aquí está mi puñalada. Rellenar los espacios en blanco". Uno de los problemas más importantes es la ambigüedad si usa colecciones y colecciones :: espacio de nombres genérico. C++/CLI es realmente un dolor.

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

Gracias. "Uno de los mayores problemas es la ambigüedad si utiliza Colecciones y Colecciones :: Espacio de nombre genérico" <- eso, y el hecho de que Intellisense (TM) sigue quejándose de los retornos covariantes independientemente incluso después de una compilación exitosa :) – sehe

+0

No debería ¿Hay una 'corriente de retorno' en el getter de' CurrentBase'? – Lars

Cuestiones relacionadas