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