2011-01-25 37 views
5

任何人都可以指示我如何編寫C#可枚舉類,以使Excel VBA中的「for each」構造能夠正常工作嗎?我嘗試了一個名爲People的測試類,它實現了IEnumerable幷包含一個Person對象數組。 「foreach」構造在C#中工作正常,但在VBA中,我只能循環使用舊式的方式。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#代碼(編譯COM在VS 2008中可見,用於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(); 
      } 
     } 
    } 
} 
+0

[相關:但基於VBA](http://stackoverflow.com/questions/19373081/how-to-use-the-implements-in-excel-vba/19379641#19379641) – 2014-06-09 07:45:24

回答

4

嘗試添加[DispId(-4)]到你的GetEnumerator()方法。這標誌着它是DISPID_NEWENUM成員。爲了讓VBA使用For Each來處理集合,它需要通過COM實現_newEnum

這可以通過實現枚舉器並將其歸入適當的DispId來完成。這通常是通過使用這個指定的自定義接口來完成的,儘管有other mechanisms可用。

+0

感謝您的快速回復。 ..我嘗試了快速修復 - 即添加[DispId(-4)] GetEnumerator。現在錯誤消息是「Property let procedure not defined and property get procedure did not return a object」。我試圖向People indexer添加一個「set」方法,但這沒有幫助。如果還有其他快速的事情要嘗試,請告訴我。同時,我正在關注您的其他建議鏈接(但這需要更多時間來消化)。謝謝 – tpascale 2011-01-25 18:32:31