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

时间:2020-03-05 18:59:18  来源:igfitidea点击:

我包装了一个本机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方式"是什么?一个单一的方法返回一个数组<>? array <>泛型是否具有迭代器,以便可以实现BeginLocals()和EndLocals()?

2)是否应在.NET包装器中将Local声明为值结构?

我真的很想用.NET风格表示包装好的类,但是对于托管世界来说我是一个新手,而这类信息对于Google来说实在令人沮丧。

解决方案

回答

迭代器不能完全翻译为" .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>接口。

几乎可以直接翻译为我们所假设的内容:

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)  
{
 ... 
}

回答

@Phillip谢谢,回答确实使我朝着正确的方向开始。

看到代码,并在Nish的《 C ++ / CLI in Action》一书中做更多的阅读之后,我认为使用索引属性将const跟踪句柄返回到托管堆上的Local实例可能是最好的方法。我最终实现了类似于以下内容的东西:

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