2011-01-25 12 views
5

Czy ktoś może mi polecić, jak kodować przeliczalne klasy C#, tak że "dla każdego" konstruktora w Excel VBA działa poprawnie? Próbowałem tego z klasą testową o nazwie Ludzie, która implementuje IEnumerable i zawiera tablicę obiektów Person. Konstrukcja "foreach" działa dobrze w języku C#, ale w VBA mogę tylko zapętlić staromodny sposób.C# klasy przeliczalne - zgodne z VBA

Ten kod VBA działa dobrze:

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 

Ale to nie w czasie wykonywania ("Obiekt nie obsługuje tej właściwości lub metody"):

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

Oto kod C# (skompilowany COM widoczne w VS 2008 do pracy z 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

[powiązane: ale oparte na VBA] (http://stackoverflow.com/questions/19373081/how-to-use-the-implements-in-excel-vba/19379641#19379641) –

Odpowiedz

4

spróbuj dodać [DispId(-4)] do metody GetEnumerator(). Oznacza to, że jest to członek DISPID_NEWENUM. Aby VBA mógł pracować z kolekcją przy użyciu funkcji Dla każdego, musi implementować _newEnum przez COM.

Można to zrobić, wdrażając moduł wyliczający i przypisując go właściwemu identyfikatorowi DispId. Zwykle odbywa się to poprzez implementację niestandardowego interfejsu z tym określonym, chociaż dostępne są other mechanisms.

+0

Dzięki za szybką odpowiedź. .. Wypróbowałem szybką naprawę - tj. Dodanie [DispId (-4)] do GetEnumerator. Teraz komunikat msg to "Nie zdefiniowano procedury udostępniania właściwości, a procedura odzyskiwania właściwości nie zwróciła obiektu". Próbowałem dodać metodę "zestawu" do indeksera Ludzie, ale to nie pomogło. Jeśli są jakieś inne szybkie rzeczy do wypróbowania, daj mi znać. Tymczasem śledzę twój inny sugerowany link (ale to zajmie trochę więcej czasu na trawienie). Dzięki – tpascale

+0

@tpascale: Myślę, że musisz stworzyć interfejs COM widoczny i mieć to zaimplementować. Powinien zawierać metodę GetEnumerator z flagą [DispId (-4)]. Zobacz ten link dla przykładów ... –

+0

Projekt jest już widoczny COM - i Excel VBA może już używać tych obiektów i pętli przy użyciu indeksu. Konstrukcja foreach działa również w języku C# - po prostu nie działa w języku VBA nawet w przypadku sztuczki DispID (-4). Kolekcje VBA nie są kolekcjami .NET, więc fakt, że działa poprawnie w .NET, ale nie w VBA, nie jest strasznie zaskakujący. W każdym razie bardzo doceniam komentarze, które wyraźnie wskazały mi właściwy kierunek (nawet jeśli nadal jestem mglisty w kwestii przekraczania linii bramkowej). – tpascale

Powiązane problemy