2011-01-25 30 views
5

Bất cứ ai có thể hướng dẫn tôi về cách mã hóa một lớp C# có thể đếm được sao cho cấu trúc "cho mỗi" trong Excel VBA hoạt động đúng không? Tôi đã thử điều này với một lớp thử nghiệm được gọi là Những người thực hiện IEnumerable và chứa một mảng các đối tượng Person. Cấu trúc "foreach" hoạt động tốt trong C#, nhưng trong VBA tôi chỉ có thể lặp lại cách cũ.C# enumerable class - tương thích với VBA

mã VBA này chỉ hoạt động tốt:

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 

Nhưng điều này không tại thời gian chạy ("Object không hỗ trợ tài sản hoặc phương pháp"):

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

Đây là mã C# (được biên dịch COM hiển thị trong VS 2008 để sử dụng với 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

[liên quan: nhưng dựa trên VBA] (http://stackoverflow.com/questions/19373081/how-to-use-the-implements-in-excel-vba/19379641#19379641) –

Trả lời

4

Thử thêm [DispId(-4)] theo phương pháp GetEnumerator() của bạn. Lá cờ này là thành viên DISPID_NEWENUM. Để VBA làm việc với một bộ sưu tập sử dụng cho Mỗi, nó cần phải thực hiện _newEnum qua COM.

Điều này có thể được thực hiện bằng cách thực hiện một Điều tra viên và phân bổ nó với DispId thích hợp. Điều này thường được thực hiện thông qua việc triển khai giao diện tùy chỉnh với giao diện được chỉ định này, mặc dù có sẵn other mechanisms.

+0

Cảm ơn bạn đã trả lời nhanh. .. Tôi đã thử sửa lỗi nhanh - nghĩa là thêm [DispId (-4)] vào GetEnumerator. Bây giờ các thông báo lỗi là "Bất động sản cho thủ tục không được xác định và tài sản có được thủ tục không trả lại một đối tượng". Tôi đã thử thêm một phương thức "set" vào People indexer, nhưng điều đó không giúp được gì. Nếu có bất kỳ điều gì khác nhanh chóng để thử, hãy cho tôi biết. Trong khi đó, tôi đang theo dõi liên kết được đề xuất khác của bạn (nhưng sẽ mất thêm một chút thời gian để tiêu hóa). Cảm ơn – tpascale

+0

@tpascale: Tôi nghĩ bạn cần tạo giao diện hiển thị COM và thực hiện điều này. Nó sẽ bao gồm phương thức GetEnumerator với [DispId (-4)] được gắn cờ trên nó. Xem liên kết đó để biết các ví dụ ... –

+0

Dự án đã được hiển thị COM - và Excel VBA có thể đã sử dụng các đối tượng này và lặp lại bằng cách sử dụng một chỉ mục. Cấu trúc foreach cũng hoạt động trong C# - không hoạt động trong VBA ngay cả với thủ thuật DispID (-4). Bộ sưu tập VBA không phải là các bộ sưu tập .NET vì vậy thực tế là nó hoạt động tốt trong .NET nhưng không phải trong VBA không phải là khủng khiếp đáng ngạc nhiên. Dù sao, tôi rất cảm kích những bình luận rõ ràng đã chỉ cho tôi đúng hướng (ngay cả khi tôi vẫn còn mù sương về cách vượt qua vạch đích). – tpascale

Các vấn đề liên quan