2011-02-23 20 views
7

¿Alguien tiene un ejemplo paso a paso de cómo implementar IEnumerable e IEnumerator en C++/CLI? Alternativamente, ¿alguien sabe cómo reparar el siguiente código de MS Connect que no se compila en Visual Studio 2005?Implementación de C++/CLI IEnumerable e IEnumerator

http://connect.microsoft.com/VisualStudio/feedback/details/101089/how-to-implement-ienumerable-t-and-ienumerable-c-cli

using namespace System; 
using namespace System::Collections::Generic; 

generic <class T> 
public ref struct MyArray : public IEnumerable<T> 
{  

    MyArray(array<T>^ d) 
    { 
     data = d; 
    } 
    ref struct enumerator : IEnumerator<T> 
    { 
     enumerator(MyArray^ myArr) 
     { 
      colInst = myArr; 
      currentIndex = -1; 
     } 

     bool MoveNext() 
     { 
      if(currentIndex < colInst->data->Length - 1) 
      { 
       currentIndex++; 
       return true; 
      } 
      return false; 
     } 

     property T Current 
     { 
      T get() 
      { 
       return colInst->data[currentIndex]; 
      } 
     }; 
     // This is required as IEnumerator<T> also implements IEnumerator 
     property Object^ Current2 
     { 
      virtual Object^ get() new sealed = System::Collections::IEnumerator::Current::get 
      { 
       return colInst->data[currentIndex]; 
      } 
     }; 

     void Reset() {} 
     ~enumerator() {} 

     MyArray^ colInst; 
     int currentIndex; 
    }; 

    array<T>^ data; 

    IEnumerator<T>^ GetEnumerator() 
    { 
     return gcnew enumerator(this); 
    } 

    virtual System::Collections::IEnumerator^ GetEnumerator2() new sealed = System::Collections::IEnumerable::GetEnumerator 
    { 
     return gcnew enumerator(this); 
    } 
}; 

int main() 
{ 
    int retval = 0; 

    MyArray<int>^ col = gcnew MyArray<int>(gcnew array<int>{10, 20, 30 }); 

    for each(Object^ c in col) 
    { 
     retval += (int)c; 
    } 
    retval -= 10 + 20 + 30; 

    Console::WriteLine("Return Code: {0}", retval); 
    return retval; 
} 

El compilador es incapaz de encontrar las implementaciones de métodos empadronador:

error C3766: 'MyArray<T>::enumerator' must provide an implementation for the interface method 'bool System::Collections::IEnumerator::MoveNext(void)' c:\Projects\VCNET\2005\IEnumerable\IEnumerable\IEnumerable.cpp 55 

error C3766: 'MyArray<T>::enumerator' must provide an implementation for the interface method 'void System::Collections::IEnumerator::Reset(void)' c:\Projects\VCNET\2005\IEnumerable\IEnumerable\IEnumerable.cpp 55 

error C3766: 'MyArray<T>::enumerator' must provide an implementation for the interface method 'T System::Collections::Generic::IEnumerator<T>::Current::get(void)' c:\Projects\VCNET\2005\IEnumerable\IEnumerable\IEnumerable.cpp 55 

error C3766: 'MyArray<T>' must provide an implementation for the interface method 'System::Collections::Generic::IEnumerator<T> ^System::Collections::Generic::IEnumerable<T>::GetEnumerator(void)' c:\Projects\VCNET\2005\IEnumerable\IEnumerable\IEnumerable.cpp 68 
+0

Try salpicando algo de "público": por las dudas. (Sí, sé que 'ref struct' debería ser público por defecto). O use la notación de anulación explícita, como lo hizo para 'Current2 :: get' y' GetEnumerator2', y deje que el compilador le explique por qué no se anula. –

+0

¿Has probado lo que dijo Jamie sobre marcar todas esas funciones 'virtual'? –

Respuesta

14

Esto compila para mí sin un solo aviso (en VS2010):

using namespace System; 
using namespace System::Collections::Generic; 

generic <class T> 
public ref struct MyArray : public IEnumerable<T> 
{  

    MyArray(array<T>^ d) 
    { 
     data = d; 
    } 
    ref struct enumerator : IEnumerator<T> 
    { 
     enumerator(MyArray^ myArr) 
     { 
      colInst = myArr; 
      currentIndex = -1; 
     } 

     virtual bool MoveNext() = IEnumerator<T>::MoveNext 
     { 
      if(currentIndex < colInst->data->Length - 1) 
      { 
       currentIndex++; 
       return true; 
      } 
      return false; 
     } 

     property T Current 
     { 
      virtual T get() = IEnumerator<T>::Current::get 
      { 
       return colInst->data[currentIndex]; 
      } 
     }; 
     // This is required as IEnumerator<T> also implements IEnumerator 
     property Object^ Current2 
     { 
      virtual Object^ get() = System::Collections::IEnumerator::Current::get 
      { 
       return colInst->data[currentIndex]; 
      } 
     }; 

     virtual void Reset() = IEnumerator<T>::Reset {} 
     ~enumerator() {} 

     MyArray^ colInst; 
     int currentIndex; 
    }; 

    array<T>^ data; 

    virtual IEnumerator<T>^ GetEnumerator() 
    { 
     return gcnew enumerator(this); 
    } 

    virtual System::Collections::IEnumerator^ GetEnumerator2() = System::Collections::IEnumerable::GetEnumerator 
    { 
     return gcnew enumerator(this); 
    } 
}; 

int main() 
{ 
    int retval = 0; 

    MyArray<int>^ col = gcnew MyArray<int>(gcnew array<int>{10, 20, 30 }); 

    for each(Object^ c in col) 
    { 
     retval += (int)c; 
    } 
    retval -= 10 + 20 + 30; 

    Console::WriteLine("Return Code: {0}", retval); 
    return retval; 
} 
+0

¡Gracias, funciona muy bien! – Theo

+0

Perdón por rezzear esto, pero ¿cómo separarías esto en archivos .h y .cpp? – Benjamin

+0

@ginkner: No lo haría, utilizaría una implementación solo de encabezado, como siempre hace C++ para las plantillas. Sin embargo, si insiste, puede definir los cuerpos de función fuera de la clase, como 'generic bool MyArray :: enumerator :: MoveNext() {...}' –

Cuestiones relacionadas