c#enumerable class – 与VBA兼容

任何人都可以告诉我如何编写C#可枚举类,以便Excel VBA中的“for each”构造正常工作吗? 我尝试了一个名为People的测试类,它实现了IEnumerable并包含一个Person对象数组。 “foreach”构造在C#中运行良好,但在VBA中我只能循环使用老式的方式。

这个VBA代码工作得很好:

Dim P As Person Dim PP As New People For i = 0 To PP.Count - 1 Set P = PP(i) Debug.Print P.firstName + " " + P.lastName Next i 

但这在运行时失败(“对象不支持此属性或方法”):

 For Each P In PP Debug.Print P.firstName + " " + P.lastName Next P 

这是C#代码(在VS 2008中可见的已编译COM,用于Excel VBA – Office 2010):

 using System; using System.Collections; using System.Runtime.InteropServices; public class Person { public Person(string fName, string lName) { this.firstName = fName; this.lastName = lName; } public string firstName; public string lastName; } public class People : IEnumerable { private Person[] _people; // array of people public Int32 Count() { return _people.Length; } // method to return array size // indexer method to enable People[i] construct, or in VBA: People(i) public Person this[Int32 PersonNo] { get { return _people[PersonNo]; } } // constructor - hardcode to initialize w 3 people (for testing) public People() { _people = new Person[3] { new Person("John", "Smith"), new Person("Jim", "Johnson"), new Person("Sue", "Rabon"), }; } // test method just to make sure the c# foreach construct works ok public void Test() { foreach (Person P in this) System.Diagnostics.Debug.WriteLine(P.firstName + " " + P.lastName); } //implementation of basic GetEnumerator IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } //implementation of People GetEnumerator public PeopleEnum GetEnumerator() { return new PeopleEnum(_people); } } // People Enumerator class definition public class PeopleEnum : IEnumerator { public Person[] _people; int position = -1; public PeopleEnum(Person[] list) { _people = list; } public bool MoveNext() { position++; return (position < _people.Length); } public void Reset() { position = -1; } object IEnumerator.Current { get { return Current; } } public Person Current { get { try { return _people[position]; } catch (IndexOutOfRangeException) { throw new InvalidOperationException(); } } } } 

尝试将[DispId(-4)]GetEnumerator()方法中。 这会将其标记为DISPID_NEWENUM成员。 为了让VBA使用For Each处理集合,它需要通过COM实现_newEnum 。

这可以通过实现一个枚举器并使用适当的DispId来实现。 这通常通过实现具有此指定的自定义接口来完成,尽管还有其他可用的机制 。