将C++/CLI中的std::vector<>::iterator转换为.NET接口

5

我正在封装一个本地的C++类,该类具有以下方法:

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)如何使用.NET表示同样类型的接口?是单个方法返回一个数组<>吗?数组<>泛型是否具有迭代器,以便我可以实现BeginLocals()和EndLocals()?

2)在.NET包装器中,Local应该声明为值结构体吗?

我真的很想用.NET风格来表示包装类,但我对托管世界非常陌生 - 而这种类型的信息很难通过谷歌搜索获得...

2个回答

5

迭代器不完全可以翻译成“ .net 的方式”,但它们大致被 IEnumerable<T> 和 IEnumerator<T> 代替。

与其

  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++;
  }

您会在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;
}

更明确地说(不隐藏IEnumerator在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;
}

正如您所看到的,foreach只是为您隐藏了.net枚举器。

因此,".net方式"实际上就是允许人们自己创建List<Local>项目。如果您想控制迭代或使集合更加自定义,请让您的集合也实现IEnumerable<T>和/或ICollection<T>接口。

一个接近c#的直接翻译就是您所假设的:

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;}
  }
}

然后用户将能够:
foreach( Local item in someNative.Locals)  
{
 ... 
}

0

@Phillip - 谢谢,你的回答真的让我朝着正确的方向开始了。

在看了你的代码并且在Nish的书C++/CLI in Action中多读了一些之后,我认为使用一个索引属性来返回一个指向托管堆上Local实例的const tracking handle可能是最好的方法。最终我实现了类似以下的东西:

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;
};

这是一个不错的方法,但你可能还想确保至少公开一个 Count 属性 :). 另外需要注意,如果不公开列表或实现 IEnumerable< T > 接口,该类将无法被 .net 3.5 中的 LINQ 扩展使用。 - Philip Rieck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接