Bagikan melalui


Penyusunan Default untuk Array

Dalam aplikasi yang seluruhnya terdiri dari kode terkelola, Common Language Runtime (CLR) mengoper tipe array sebagai parameter In/Out. Sebaliknya, interop marshaller melewatkan array sebagai parameter In secara default.

Dengan pengoptimalan pemosisian, array yang bisa di-convert langsung dapat berfungsi sebagai parameter masuk/keluar saat berinteraksi dengan objek dalam apartemen yang sama. Namun, jika nanti Anda mengekspor kode ke perpustakaan tipe yang digunakan untuk menghasilkan proksi lintas-mesin, dan perpustakaan tersebut digunakan untuk mengolah panggilan Anda di seluruh apartemen, panggilan dapat kembali ke perilaku parameter In yang sebenarnya.

Array pada dasarnya kompleks, dan perbedaan antara array yang dikelola dan yang tidak dikelola membutuhkan lebih banyak penjelasan daripada jenis non-blittable lainnya.

Array Terkelola

Jenis array terkelola dapat bervariasi; namun, kelas System.Array adalah kelas dasar dari semua jenis array. Kelas System.Array memiliki properti untuk menentukan peringkat, panjang, dan batas bawah dan atas larik, serta metode untuk mengakses, menyortir, menelusuri, menyalin, dan membuat larik.

Jenis array ini bersifat dinamis dan tidak memiliki jenis statis terkait yang ditentukan di pustaka kelas dasar. Lebih mudah untuk memikirkan setiap kombinasi jenis elemen dan peringkat sebagai jenis array yang berbeda. Oleh karena itu, array satu dimensi dari bilangan bulat adalah tipe yang berbeda dari array satu dimensi tipe ganda. Demikian pula array bilangan bulat dua dimensi berbeda dari array bilangan bulat satu dimensi. Batas array tidak dipertimbangkan saat membandingkan jenis.

Seperti yang ditunjukkan tabel berikut, setiap instans dari array terkelola harus memiliki jenis elemen tertentu, peringkat, dan batas bawah.

Jenis array terkelola Jenis elemen Pangkat Batas bawah Notasi tanda tangan
ELEMENT_TYPE_ARRAY Ditentukan berdasarkan jenis Ditentukan oleh peringkat Secara opsional ditentukan oleh batas type[n,m]
ELEMENT_TYPE_CLASS Tidak dikenal Tidak dikenal Tidak dikenal System.Array
ELEMENT_TYPE_SZARRAY Ditentukan berdasarkan jenis 1 0 jenis[n]

Array Tidak Terkelola

Array yang tidak dikelola adalah array COM-style safe atau array gaya C dengan panjang tetap atau panjang variabel. Array aman adalah array yang memiliki deskripsi sendiri dan membawa jenis, peringkat, serta batas dari data dalam array yang terkait. Array bergaya C adalah array bertipe satu dimensi dengan batas bawah tetap 0. Layanan marshalling memiliki dukungan terbatas untuk kedua tipe array.

Melewati Parameter Array ke .NET Code

Baik array gaya-C maupun array aman dapat diteruskan ke kode .NET dari kode yang tidak dikelola baik sebagai array aman atau array gaya-C. Tabel berikut menunjukkan nilai jenis yang tidak dikelola dan jenis yang diimpor.

Jenis tidak terkelola Jenis yang diimpor
SafeArray(Type) ELEMENT_TYPE_SZARRAY<ConvertedType>

Peringkat = 1, batas bawah = 0. Ukuran hanya diketahui jika disediakan dalam tanda tangan terkelola. Array aman yang tidak berdimensi 1 atau tidak memiliki batas bawah 0 tidak dapat ditransformasikan sebagai SZARRAY.
Tipe[] ELEMENT_TYPE_SZARRAY<ConvertedType>

Peringkat = 1, batas bawah = 0. Ukuran hanya diketahui jika disediakan dalam tanda tangan terkelola.

Array yang Aman

Saat array aman diimpor dari perpustakaan tipe ke assembly .NET, array dikonversi menjadi array satu dimensi dari jenis yang diketahui (seperti int). Aturan konversi jenis yang sama yang berlaku untuk parameter juga berlaku untuk elemen array. Misalnya, array BSTR jenis yang aman menjadi array string terkelola dan array varian yang aman menjadi array objek terkelola. Tipe elemen SAFEARRAY ditangkap dari pustaka tipe dan disimpan dalam nilai SAFEARRAY dari enumerasi UnmanagedType.

Karena peringkat dan batas array aman tidak dapat ditentukan dari pustaka jenis, peringkat dianggap sama dengan 1 dan batas bawah dianggap sama dengan 0. Peringkat dan batas harus ditentukan dalam tanda tangan terkelola yang dihasilkan oleh Type Library Importer (Tlbimp.exe). Jika pada runtime peringkat yang diteruskan ke metode berbeda, sebuah SafeArrayRankMismatchException akan dilemparkan. Jika jenis array yang diteruskan pada runtime berbeda, maka SafeArrayTypeMismatchException akan dilemparkan. Contoh berikut menunjukkan array aman dalam kode yang dikelola dan tidak dikelola.

Tanda tangan tidak terkelola

HRESULT New1([in] SAFEARRAY( int ) ar);
HRESULT New2([in] SAFEARRAY( DATE ) ar);
HRESULT New3([in, out] SAFEARRAY( BSTR ) *ar);

Tanda tangan terkelola

Sub New1(<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VT_I4)> _
   ar() As Integer)
Sub New2(<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VT_DATE)> _
   ar() As DateTime)
Sub New3(ByRef <MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VT_BSTR)> _
   ar() As String)
void New1([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VT_I4)] int[] ar) ;
void New2([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VT_DATE)]
   DateTime[] ar);
void New3([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VT_BSTR)]
   ref String[] ar);

Array aman multidimensi, atau berbatas selain nol, dapat dimasukkan ke dalam kode terkelola jika tanda tangan metode yang dihasilkan oleh Tlbimp.exe dimodifikasi untuk menunjukkan jenis elemen ELEMENT_TYPE_ARRAY daripada ELEMENT_TYPE_SZARRAY. Atau, Anda dapat menggunakan sakelar /sysarray dengan Tlbimp.exe untuk mengimpor semua array sebagai objek System.Array. Dalam kasus di mana array yang diteruskan diketahui multidimensi, Anda dapat mengedit kode bahasa perantara umum (CIL) yang dihasilkan oleh Tlbimp.exe dan kemudian mengkompilasinya kembali. Untuk detail tentang cara mengubah kode CIL, lihat Menyesuaikan Runtime Callable Wrappers.

Array Gaya C

Saat array gaya C diimpor dari perpustakaan tipe ke assembly .NET, array akan dikonversi ke ELEMENT_TYPE_SZARRAY.

Jenis elemen array ditentukan dari pustaka tipe dan dipertahankan selama impor. Aturan konversi yang sama yang berlaku untuk parameter juga berlaku untuk elemen array. Misalnya, array jenis LPStr menjadi array jenis String . Tlbimp.exe menangkap jenis elemen array dan menerapkan atribut MarshalAsAttribute ke parameter.

Pangkat array diasumsikan sama dengan 1. Jika peringkat lebih besar dari 1, array dipetakan sebagai array satu dimensi dengan urutan kolom mayor. Batas bawah selalu sama dengan 0.

Pustaka tipe dapat berisi array dengan panjang tetap atau variabel. Tlbimp.exe hanya dapat mengimpor array dengan panjang tetap dari pustaka jenis karena pustaka jenis tidak memiliki informasi yang diperlukan untuk menyusun array dengan panjang variabel. Dengan array berdimensi tetap, ukuran diimpor dari pustaka tipe dan ditangkap dalam MarshalAsAttribute yang diterapkan ke parameter.

Anda harus secara manual menentukan pustaka tipe yang berisi array panjang variabel, seperti yang diperlihatkan dalam contoh berikut.

Tanda tangan tidak terkelola

HRESULT New1(int ar[10]);
HRESULT New2(double ar[10][20]);
HRESULT New3(LPWStr ar[10]);

Tanda tangan terkelola

Sub New1(<MarshalAs(UnmanagedType.LPArray, SizeConst=10)> _
   ar() As Integer)
Sub New2(<MarshalAs(UnmanagedType.LPArray, SizeConst=200)> _
   ar() As Double)
Sub New2(<MarshalAs(UnmanagedType.LPArray, _
   ArraySubType=UnmanagedType.LPWStr, SizeConst=10)> _
   ar() As String)
void New1([MarshalAs(UnmanagedType.LPArray, SizeConst=10)] int[] ar);
void New2([MarshalAs(UnmanagedType.LPArray, SizeConst=200)] double[] ar);
void New2([MarshalAs(UnmanagedType.LPArray,
   ArraySubType=UnmanagedType.LPWStr, SizeConst=10)] String[] ar);

Meskipun Anda dapat menerapkan size_is atau length_is atribut ke array di sumber Bahasa Definisi Antarmuka (IDL) untuk menyampaikan ukuran ke klien, pengkompilasi Microsoft Interface Definition Language (MIDL) tidak menyebarkan informasi tersebut ke pustaka tipe. Tanpa mengetahui ukurannya, layanan interop marshalling tidak dapat memproses elemen array. Akibatnya, array panjang variabel diimpor sebagai argumen referensi. Contohnya:

Tanda tangan tidak terkelola

HRESULT New1(int ar[]);
HRESULT New2(int ArSize, [size_is(ArSize)] double ar[]);
HRESULT New3(int ElemCnt, [length_is(ElemCnt)] LPStr ar[]);

Tanda tangan terkelola

Sub New1(ByRef ar As Integer)
Sub New2(ByRef ar As Double)
Sub New3(ByRef ar As String)
void New1(ref int ar);
void New2(ref double ar);
void New3(ref String ar);

Anda dapat menyediakan ukuran array marshaller dengan mengedit kode bahasa perantara umum (CIL) yang dihasilkan oleh Tlbimp.exe lalu mengkompilasi ulang. Untuk rincian tentang cara mengubah kode CIL, lihat Menyesuaikan Pembungkus Dapat Dipanggil pada Waktu Aktif. Untuk menunjukkan jumlah elemen dalam array, terapkan jenis MarshalAsAttribute ke parameter array dari definisi metode terkelola dengan salah satu cara berikut:

  • Identifikasi parameter lain yang berisi jumlah elemen dalam array. Parameter diidentifikasi berdasarkan posisi, dimulai dengan parameter pertama sebagai angka 0.

    Sub [New](ElemCnt As Integer, _
       <MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> _
       ar() As Integer)
    
    void New(
       int ElemCnt,
       [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] int[] ar );
    
  • Tentukan ukuran array sebagai konstanta. Contohnya:

    Sub [New](<MarshalAs(UnmanagedType.LPArray, SizeConst:=128)> _
       ar() As Integer)
    
    void New(
       [MarshalAs(UnmanagedType.LPArray, SizeConst=128)] int[] ar );
    

Saat memindahkan data array dari kode yang tidak dikelola ke kode terkelola, marshaller memeriksa MarshalAsAttribute yang terkait dengan parameter untuk menentukan ukuran array. Jika ukuran array tidak ditentukan, hanya satu elemen yang dimarshall.

Catatan

MarshalAsAttribute tidak berpengaruh pada proses marshalling array yang dikelola ke kode yang tidak dikelola. Ke arah itu, ukuran array ditentukan oleh pemeriksaan. Tidak ada cara untuk mengatur subset dari array terkelola.

Interop marshaller menggunakan metode CoTaskMemAlloc dan CoTaskMemFree di Windows atau metode malloc dan free pada sistem operasi lain untuk mengalokasikan dan mengambil kembali memori. Alokasi memori yang dilakukan oleh kode tak terkelola juga harus menggunakan metode ini.

Meneruskan Array ke COM

Semua jenis array terkelola dapat diteruskan dari kode yang dikelola ke kode yang tidak dikelola. Bergantung pada jenis terkelola dan atribut yang diterapkan padanya, array dapat diakses sebagai array yang aman atau array gaya C, seperti yang diperlihatkan dalam tabel berikut.

Jenis array terkelola Diekspor sebagai
ELEMENT_TYPE_SZARRAY<jenis> UnmanagedType . SafeArray(jenis)

UnmanagedType.LPArray

Jenis disediakan dalam tanda tangan. Peringkat selalu 1, batas bawah selalu 0. Ukuran selalu diketahui saat runtime.
ELEMENT_TYPE_ARRAY<type><rank>[<batas>] UnmanagedType.SafeArray(type)

UnmanagedType.LPArray

Jenis, peringkat, batas disediakan dalam tanda tangan. Ukuran selalu diketahui saat runtime.
ELEMENT_TYPE_CLASS <System.Array> UT_Interface

UnmanagedType.SafeArray(type)

Jenis, peringkat, batas, dan ukuran selalu diketahui saat runtime.

Ada batasan dalam OLE Automation terkait dengan susunan struktur yang berisi LPSTR atau LPWSTR. Oleh karena itu, String bidang data harus diselaraskan sebagai UnmanagedType.BSTR. Jika tidak, suatu pengecualian akan dilemparkan.

ELEMENT_TYPE_SZARRAY

Saat sebuah metode yang berisi parameter ELEMENT_TYPE_SZARRAY (array satu dimensi) diekspor dari rakitan .NET ke pustaka tipe, parameter array tersebut dikonversi menjadi SAFEARRAY dari jenis tertentu. Aturan konversi yang sama berlaku untuk jenis elemen array. Konten array terkelola secara otomatis disalin dari memori terkelola ke SAFEARRAY. Contohnya:

Tanda tangan terkelola

Sub [New](ar() As Long)
Sub [New](ar() As String)
void New(long[] ar );
void New(String[] ar );

Tanda tangan tidak terkelola

HRESULT New([in] SAFEARRAY( long ) ar);
HRESULT New([in] SAFEARRAY( BSTR ) ar);

Pangkat dari array aman selalu 1 dan batas bawah selalu 0. Ukuran ditentukan pada runtime berdasarkan ukuran array terkelola yang diteruskan.

Array juga dapat diubah menjadi C-style array dengan menggunakan atribut MarshalAsAttribute. Contohnya:

Tanda tangan terkelola

Sub [New](<MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> _
   ar() As Long, size as Integer)
Sub [New](<MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> _
   ar() As String, size as Integer)
Sub [New](<MarshalAs(UnmanagedType.LPArray, _
   ArraySubType= UnmanagedType.LPStr, SizeParamIndex:=1)> _
   ar() As String, size as Integer)
void New([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]
   long [] ar, int size );
void New([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]
   String [] ar, int size );
void New([MarshalAs(UnmanagedType.LPArray, ArraySubType=
   UnmanagedType.LPStr, SizeParamIndex=1)]
   String [] ar, int size );

Tanda tangan tidak terkelola

HRESULT New(long ar[]);
HRESULT New(BSTR ar[]);
HRESULT New(LPStr ar[]);

Meskipun marshaller memiliki informasi panjang yang diperlukan untuk menyusun array, ukuran array biasanya diteruskan sebagai argumen terpisah untuk menyampaikan ukurannya kepada penerima.

ELEMENT_TYPE_ARRAY

Saat metode yang mengandung parameter ELEMENT_TYPE_ARRAY diekspor dari rakitan .NET ke pustaka jenis, parameter larik dikonversi ke SAFEARRAY jenis tertentu. Konten array terkelola secara otomatis disalin dari memori terkelola ke SAFEARRAY. Contohnya:

Tanda tangan terkelola

Sub [New](ar(,) As Long)
Sub [New](ar(,) As String)
void New( long [,] ar );
void New( String [,] ar );

Tanda tangan tidak terkelola

HRESULT New([in] SAFEARRAY( long ) ar);
HRESULT New([in] SAFEARRAY( BSTR ) ar);

Peringkat, ukuran, dan batas array aman ditentukan pada runtime berdasarkan karakteristik array terkelola.

Array juga dapat diatur sebagai array bergaya-C dengan menerapkan atribut MarshalAsAttribute. Contohnya:

Tanda tangan terkelola

Sub [New](<MarshalAs(UnmanagedType.LPARRAY, SizeParamIndex:=1)> _
   ar(,) As Long, size As Integer)
Sub [New](<MarshalAs(UnmanagedType.LPARRAY, _
   ArraySubType:=UnmanagedType.LPStr, SizeParamIndex:=1)> _
   ar(,) As String, size As Integer)
void New([MarshalAs(UnmanagedType.LPARRAY, SizeParamIndex=1)]
   long [,] ar, int size );
void New([MarshalAs(UnmanagedType.LPARRAY,
   ArraySubType= UnmanagedType.LPStr, SizeParamIndex=1)]
   String [,] ar, int size );

Tanda tangan tidak terkelola

HRESULT New(long ar[]);
HRESULT New(LPStr ar[]);

Array berlapis tidak dapat di-marshal. Misalnya, tanda tangan berikut menghasilkan kesalahan saat diekspor dengan Pengekspor Pustaka Tipe (Tlbexp.exe).

Tanda tangan terkelola

Sub [New](ar()()() As Long)
void New(long [][][] ar );

<ELEMENT_TYPE_CLASS System.Array>

Ketika sebuah metode yang berisi parameter System.Array diekspor dari rakitan .NET ke pustaka tipe, parameter array tersebut dikonversi menjadi antarmuka _Array. Konten array terkelola hanya dapat diakses melalui metode dan properti _Array antarmuka. System.Array juga dapat dimarshall sebagai SAFEARRAY dengan menggunakan atribut MarshalAsAttribute. Ketika dinamakan sebagai array yang aman, elemen array dinamai sebagai varian. Contohnya:

Tanda tangan terkelola

Sub New1( ar As System.Array )
Sub New2( <MarshalAs(UnmanagedType.SafeArray)> ar As System.Array )
void New1( System.Array ar );
void New2( [MarshalAs(UnmanagedType.SafeArray)] System.Array ar );

Tanda tangan tidak terkelola

HRESULT New([in] _Array *ar);
HRESULT New([in] SAFEARRAY(VARIANT) ar);

Array dalam Struktur

Struktur yang tidak dikelola dapat berisi array yang disematkan. Secara default, bidang array yang disematkan ini disusun sebagai SAFEARRAY. Dalam contoh berikut, s1 adalah array tersemat yang dialokasikan langsung dalam struktur itu sendiri.

Representasi tidak dikelola

struct MyStruct {
    short s1[128];
}

Array dapat disusun sebagai UnmanagedType, yang mengharuskan Anda menyetel bidang MarshalAsAttribute. Ukuran hanya dapat diatur sebagai konstanta. Kode berikut menunjukkan definisi terkelola yang sesuai dari MyStruct.

Public Structure <StructLayout(LayoutKind.Sequential)> MyStruct
   Public <MarshalAs(UnmanagedType.ByValArray, SizeConst := 128)> _
     s1() As Short
End Structure
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct {
   [MarshalAs(UnmanagedType.ByValArray, SizeConst=128)] public short[] s1;
}

Lihat juga