Bagikan melalui


Penyusunan Default untuk Array

Dalam aplikasi yang seluruhnya terdiri dari kode terkelola, runtime bahasa umum melewati tipe array sebagai parameter Masuk/Keluar. Sebaliknya, interop marshaller melewati array sebagai parameter masuk secara default.

Dengan pengoptimalan penyematan, array yang dapat di-blittable dapat tampak beroperasi sebagai parameter Masuk/Keluar saat berinteraksi dengan objek di apartemen yang sama. Namun, jika nanti Anda mengekspor kode ke pustaka jenis yang digunakan untuk menghasilkan proksi lintas-mesin, dan pustaka tersebut digunakan untuk menyusun panggilan Anda di seluruh apartemen, panggilan dapat kembali ke perilaku parameter masuk yang sebenarnya.

Array pada dasarnya kompleks, dan perbedaan antara array yang dikelola dan tidak dikelola memerlukan lebih banyak informasi 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 berdasarkan peringkat. Opsional ditentukan oleh batas. jenis[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 aman gaya-COM atau array gaya-C dengan panjang tetap atau variabel. Array aman adalah array yang menggambarkan diri sendiri yang membawa jenis, peringkat, dan batas dari data array terkait. Array gaya-C adalah array berjenis satu dimensi dengan batas bawah tetap 0. Layanan marshalling memiliki dukungan terbatas untuk kedua jenis 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(Jenis) ELEMENT_TYPE_SZARRAY<ConvertedType>

Peringkat = 1, batas bawah = 0. Ukuran hanya diketahui jika disediakan dalam tanda tangan terkelola. Array aman yang bukan peringkat = 1 atau batas bawah = 0 tidak dapat disusun sebagai SZARRAY.
Jenis[] ELEMENT_TYPE_SZARRAY<ConvertedType>

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

Array Aman

Saat array aman diimpor dari pustaka jenis ke rakitan .NET, array akan dikonversi ke 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 aman jenis BSTR menjadi array string terkelola dan array varian aman menjadi array objek terkelola. Jenis elemen SAFEARRAY diambil dari pustaka jenis 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 peringkat yang diteruskan ke metode pada waktu proses berbeda, SafeArrayRankMismatchException ditampilkan. Jika jenis array yang diteruskan pada waktu proses berbeda, SafeArrayTypeMismatchException akan ditampilkan. Contoh berikut menunjukkan array aman dalam kode terkelola dan tidak terkelola.

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 tidak terikat nol, dapat disusun menjadi kode terkelola jika tanda tangan metode yang dihasilkan oleh Tlbimp.exe dimodifikasi untuk menunjukkan jenis elemen ELEMENT_TYPE_ARRAY alih-alih 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 multidirmani, Anda dapat mengedit kode bahasa perantara umum (CIL) yang dihasilkan oleh Tlbimp.exe dan kemudian mengkompilasi ulang. Untuk detail tentang cara mengubah kode CIL, lihat Menyesuaikan Runtime Pembungkus yang Dapat Dipanggil.

Array Gaya-C

Saat array gaya-C diimpor dari pustaka jenis ke rakitan .NET, array akan dikonversi ke ELEMENT_TYPE_SZARRAY.

Jenis elemen array ditentukan dari pustaka jenis 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 disusun sebagai array satu dimensi dalam urutan kolom-utama. Batas bawah selalu sama dengan 0.

Pustaka jenis 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 dengan panjang tetap, ukuran diimpor dari pustaka jenis dan ditangkap di MarshalAsAttribute yang diterapkan ke parameter.

Anda harus secara manual menentukan pustaka jenis 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);

Meski Anda dapat menerapkan atribut size_is atau length_is ke array di sumber Bahasa Definisi Antarmuka (IDL) untuk menyampaikan ukuran ke klien, kompilator Microsoft Interface Definition Language (MIDL) tidak menyebarluaskan informasi tersebut ke pustaka tipe. Tanpa mengetahui ukurannya, layanan interop marshalling tidak dapat menyusun 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 detail tentang cara mengubah kode CIL, lihat Menyesuaikan Runtime Pembungkus yang Dapat Dipanggil. 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 menyusun array dari kode tidak terkelola ke kode terkelola, marshaller memeriksa MarshalAsAttribute yang terkait dengan parameter untuk menentukan ukuran array. Jika ukuran array tidak ditentukan, hanya satu elemen yang diatur.

Catatan

MarshalAsAttribute tidak berpengaruh dalam menyusun array terkelola ke kode yang tidak terkelola. Ke arah itu, ukuran array ditentukan oleh pemeriksaan. Tidak ada cara untuk marsekal subset array terkelola.

Marshaller interop menggunakan metode CoTaskMemAlloc dan CoTaskMemFree pada Windows atau malloc dan metode gratis pada sistem operasi lain untuk mengalokasikan dan mengambil memori. Alokasi memori yang dilakukan oleh kode tak terkelola juga harus menggunakan metode ini.

Meneruskan Array ke COM

Semua jenis array terkelola dapat diteruskan ke kode yang tidak dikelola dari kode yang dikelola. Bergantung pada jenis terkelola dan atribut yang diterapkan padanya, array dapat diakses sebagai array 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 pada saat dijalankan.
ELEMENT_TYPE_ARRAY<jenis><pangkat> [<terikat>] UnmanagedType.SafeArray(jenis)

UnmanagedType.LPArray

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

UnmanagedType.SafeArray(jenis)

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

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

ELEMENT_TYPE_SZARRAY

Saat metode yang berisi parameter ELEMENT_TYPE_SZARRAY (array satu dimensi) diekspor dari rakitan .NET ke pustaka jenis, parameter array dikonversi ke 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 durasi berdasarkan ukuran array terkelola yang dilewati.

Array juga dapat disusun sebagai array gaya-C 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, panjang array biasanya diteruskan sebagai argumen terpisah untuk menyampaikan panjang ke callee.

ELEMENT_TYPE_ARRAY

Saat metode yang berisi parameter ELEMENT_TYPE_ARRAY diekspor dari rakitan .NET ke pustaka jenis, parameter array dikonversi ke SAFEARRAY dari 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);

Pangkat, ukuran, dan batas array aman ditentukan pada durasi berdasarkan karakteristik array terkelola.

Array juga dapat disusun sebagai array gaya-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>

Saat metode yang berisi parameter System.Array diekspor dari rakitan .NET ke pustaka jenis, parameter array dikonversi ke antarmuka _Array. Konten array terkelola hanya dapat diakses melalui metode dan properti antarmuka _Array. System.Array juga dapat dijadikan marshal 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.Safe array)> ar As System.Array )
void New1( System.Array ar );
void New2( [MarshalAs(UnmanagedType.Safe array)] 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 terkelola

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