I am wrapping a native C++ class, which has the following methods:
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) What is the ".NET way" of representing this same kind of interface? A single method returning an array<>? Does the array<> generic have iterators, so that I could implement BeginLocals() and EndLocals()?
2) Should Local be declared as a value struct in the .NET wrapper?
I'd really like to represent the wrapped class with a .NET flavor, but I'm very new to the managed world - and this type of information is frustrating to google for...
-
Iterators aren't exactly translatable to "the .net way", but they are roughly replaced by IEnumerable < T > and IEnumerator < T >.
Rather than
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++; }
you would see (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; }
Or more explicitly (without hiding the IEnumerator behind the foreach syntax sugar):
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; }
As you can see, foreach just hides the .net enumerator for you.
So really, the ".net way" would be to simply allow people to create List< Local > items for themselves. If you do want to control iteration or make the collection a bit more custom, have your collection implement the IEnumerable< T > and/or ICollection< T > interfaces as well.
A near direct translation to c# would be pretty much what you assumed:
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;} } }
Then a user would be able to
foreach( Local item in someNative.Locals) { ... }
From Philip Rieck -
@Phillip - Thanks, your answer really got me started in the right direction.
After seeing your code, and doing a little more reading in Nish's book C++/CLI in Action, I think using an indexed property that returns a const tracking handle to a Local instance on the managed heap is probably the best approach. I ended up implementing something similar to the following:
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; };
Philip Rieck : That's a good approach, but you'll probably want to also make sure to expose a Count property at least :). One other note, without exposing the list or implementing IEnumerable< T >, the class won't be usable by the LINQ extensions in .net 3.5From Brian Stewart
0 comments:
Post a Comment