【问题标题】:Implementing IEnumerable<T> in C++/CLI在 C++/CLI 中实现 IEnumerable<T>
【发布时间】:2011-01-09 03:57:21
【问题描述】:

我在 C++/CLI 的自定义集合类中实现 IEnumerable&lt;T&gt; 时遇到问题。这是代码的相关部分:

using namespace System::Collections::Generic;

ref class MyCollection : IEnumerable<MyClass^>
{
public:
    MyCollection()
    {
    }  

    virtual IEnumerator<MyClass^>^ GetEnumerator()
    {
        return nullptr;
    }
};

编译时,这会导致以下错误:

错误 C2392: 'System::Collections::Generic::IEnumerator ^MyCollection::GetEnumerator(void)': 协变返回类型不是 在托管类型中支持,否则 '系统::集合::IEnumerator ^System::Collections::IEnumerable::GetEnumerator(void)' 将被覆盖错误 C3766: “MyCollection”必须提供 接口的实现 方法 '系统::集合::IEnumerator ^System::Collections::IEnumerable::GetEnumerator(void)'

这是有道理的,因为IEnumerable&lt;T&gt; 派生自IEnumerable。但是,我不确定如何修复此编译错误。如果这是 C#,我会隐式实现 IEnumerable,但是我不确定如何在 C++/CLI 中执行此操作(如果可能的话),如下所示:

class MyCollection : IEnumerable<MyClass>
{
    public MyCollection()
    {
    }

    public IEnumerator<MyClass> GetEnumerator()
    {
        return null;
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

如果我确实添加了IEnumerable::GetEnumerator() 的实现,编译器会抱怨两种仅在返回类型上有所不同的方法(这也是有道理的)。

那么,如何在 C++/CLI 类中实现IEnumerable&lt;T&gt;

【问题讨论】:

标签: .net c++-cli


【解决方案1】:

您必须提供the non-generic GetEnumerator() method 的显式实现并包含非通用命名空间:

using namespace System::Collections;

....

virtual IEnumerator^ EnumerableGetEnumerator() = IEnumerable::GetEnumerator
{
    return GetEnumerator<MyClass^>();
}

更新:正如 cmets 中提到的,GetEnumerator 的显式版本必须命名不同以避免名称冲突,因此我将其命名为 EnumerableGetEnumerator。

同样,在 C# 中,您必须这样做:

using System.Collections.Generic;

public class MyCollection : IEnumerable<MyClass>
{
    public MyCollection()
    {
    }  

    public IEnumerator<MyClass> GetEnumerator()
    {
        return null;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator<MyClass>();
    }
}

【讨论】:

  • 仅仅实现 GetEnumerator() 是行不通的。如果这样做,我会收到一个编译器错误,指出重载函数不能仅通过返回类型来区分。
  • 更新了我如何在 C# 中实现它的问题
  • 猜猜我在这里有点快......现在它应该可以工作了。否则,我会朝自己的脚开枪。
  • 是的,这行得通。我刚刚从谷歌找到了同样的东西。谢谢您的帮助。 :)
  • 一个细微的变化:您的第一个代码示例中的 GetEnumerator() 需要重命名为其他名称以避免名称冲突。我使用了 GetEnumerator2(),虽然它并不重要。
【解决方案2】:

这不是很简单。这是我的尝试。填写“空白”。如果同时使用 Collections 和 Collections::Generic 命名空间,最大的问题之一就是歧义。 C++/CLI 真的很痛苦。

using namespace System;
using namespace System::Collections;

public ref struct Enumerable : public Generic::IEnumerable<String^> {

public:
    virtual Generic::IEnumerator<String^>^ GetEnumerator() sealed = Generic::IEnumerable<String^>::GetEnumerator { 
        return gcnew Enumerator(); 
    }

    virtual IEnumerator^ GetEnumeratorBase() sealed = IEnumerable::GetEnumerator { 
        return GetEnumerator(); 
    }

private:
    ref struct TagEnumerator : public Generic::IEnumerator<String^> {

    public:
        property String^ Current { 
            virtual String^ get() {
                throw gcnew NotImplementedException(); 
            } 
        };

        property Object^ CurrentBase { 
            virtual Object^ get() sealed = IEnumerator::Current::get { 
                throw gcnew NotImplementedException(); 
            } 
        };

        virtual bool MoveNext() { 
            throw gcnew NotImplementedException(); 
        }

        virtual void Reset() { 
            throw gcnew NotImplementedException(); 
        }

        virtual ~Enumerator() {
        }
    };
};

【讨论】:

  • 谢谢。 “如果同时使用 Collections 和 Collections::Generic 命名空间,最大的问题之一就是模棱两可”
  • CurrentBase的getter中不应该有return Current吗?
猜你喜欢
  • 1970-01-01
  • 2014-12-04
  • 1970-01-01
  • 2015-03-12
  • 2012-07-03
  • 2014-12-20
  • 1970-01-01
  • 2011-07-29
  • 2012-02-04
相关资源
最近更新 更多