Conversione di std::vettore<>::iterator nell'interfaccia .NET in C++/CLI
-
01-07-2019 - |
Domanda
Sto avvolgendo una classe C++ nativa, che ha i seguenti metodi:
class Native
{
public:
class Local
{
std::string m_Str;
int m_Int;
};
typedef std::vector<Local> LocalVec;
typedef LocalVec::iterator LocalIter;
LocalIter BeginLocals();
LocalIter EndLocals();
private:
LocalVec m_Locals;
};
1) Qual è il "modo .NET" di rappresentare questo stesso tipo di interfaccia?Un singolo metodo che restituisce un array<>?L'array<> generico ha iteratori, in modo da poter implementare BeginLocals() e EndLocals()?
2) Locale dovrebbe essere dichiarato come a struttura del valore nel wrapper .NET?
Mi piacerebbe davvero rappresentare la classe incapsulata con un sapore .NET, ma sono molto nuovo nel mondo gestito e questo tipo di informazioni è frustrante da cercare su Google...
Soluzione
Gli iteratori non sono esattamente traducibili in "modo .net", ma sono approssimativamente sostituiti da IEnumerable < T > e IEnumerator < T >.
Piuttosto che
vector<int> a_vector;
vector<int>::iterator a_iterator;
for(int i= 0; i < 100; i++)
{
a_vector.push_back(i);
}
int total = 0;
a_iterator = a_vector.begin();
while( a_iterator != a_vector.end() ) {
total += *a_iterator;
a_iterator++;
}
vedresti (in C#)
List<int> a_list = new List<int>();
for(int i=0; i < 100; i++)
{
a_list.Add(i);
}
int total = 0;
foreach( int item in a_list)
{
total += item;
}
O più esplicitamente (senza nascondere l'IEnumerator dietro lo zucchero della sintassi foreach):
List<int> a_list = new List<int>();
for (int i = 0; i < 100; i++)
{
a_list.Add(i);
}
int total = 0;
IEnumerator<int> a_enumerator = a_list.GetEnumerator();
while (a_enumerator.MoveNext())
{
total += a_enumerator.Current;
}
Come puoi vedere, foreach nasconde semplicemente l'enumeratore .net.
Quindi, in realtà, il "metodo .net" sarebbe semplicemente consentire alle persone di creare elementi List< Local > per se stessi.Se vuoi controllare l'iterazione o rendere la raccolta un po' più personalizzata, fai in modo che la tua raccolta implementi anche le interfacce IEnumerable< T > e/o ICollection< T >.
Una traduzione quasi diretta in c# sarebbe più o meno quella che hai ipotizzato:
public class Native
{
public class Local
{
public string m_str;
public int m_int;
}
private List<Local> m_Locals = new List<Local>();
public List<Local> Locals
{
get{ return m_Locals;}
}
}
Quindi un utente sarebbe in grado di farlo
foreach( Local item in someNative.Locals)
{
...
}
Altri suggerimenti
@Phillip - Grazie, la tua risposta mi ha davvero fatto iniziare nella giusta direzione.
Dopo aver visto il tuo codice e aver letto ancora un po' il libro di Nish C++/CLI in azione, penso che l'utilizzo di una proprietà indicizzata che restituisce un handle di tracciamento const a un'istanza locale sull'heap gestito sia probabilmente l'approccio migliore.Alla fine ho implementato qualcosa di simile al seguente:
public ref class Managed
{
public:
ref class Local
{
String^ m_Str;
int m_Int;
};
property const Local^ Locals[int]
{
const Local^ get(int Index)
{
// error checking here...
return m_Locals[Index];
}
};
private:
List<Local^> m_Locals;
};