Delen via


Standaard marshalling voor matrices

In een toepassing die volledig uit beheerde code bestaat, geeft de algemene taalruntime matrixtypen door als in/uit-parameters. De interop marshaller geeft daarentegen standaard een matrix door als In-parameters.

Met het vastmaken van optimalisatie kan een belichte matrix lijken te werken als een In/Out-parameter bij interactie met objecten in hetzelfde appartement. Als u de code later echter exporteert naar een typebibliotheek die wordt gebruikt voor het genereren van de proxy voor meerdere computers en die bibliotheek wordt gebruikt om uw aanroepen tussen appartementen te marshalen, kunnen de aanroepen terugkeren naar true In parametergedrag.

Matrices zijn van nature complex en het onderscheid tussen beheerde en onbeheerde matrices rechtvaardigt meer informatie dan andere niet-belichte typen.

Beheerde matrices

Beheerde matrixtypen kunnen variëren; De System.Array klasse is echter de basisklasse van alle matrixtypen. De klasse System.Array heeft eigenschappen voor het bepalen van de rang, lengte en onder- en bovengrenzen van een matrix, evenals methoden voor het openen, sorteren, zoeken, kopiëren en maken van matrices.

Deze matrixtypen zijn dynamisch en hebben geen bijbehorend statisch type gedefinieerd in de basisklassebibliotheek. Het is handig om elke combinatie van elementtype en rangschikking als een uniek type matrix te beschouwen. Daarom is een eendimensionale matrix met gehele getallen van een ander type dan een eendimensionale matrix van dubbele typen. Een tweedimensionale matrix met gehele getallen verschilt van een eendimensionale matrix met gehele getallen. De grenzen van de matrix worden niet meegenomen bij het vergelijken van typen.

Zoals in de volgende tabel wordt weergegeven, moet elk exemplaar van een beheerde matrix van een specifiek elementtype, rang en ondergrens zijn.

Beheerd matrixtype Elementtype Positie Ondergrens Handtekening notatie
ELEMENT_TYPE_ARRAY Opgegeven op type. Opgegeven door rang. Optioneel opgegeven door grenzen. type [ n,m ]
ELEMENT_TYPE_CLASS Onbekend Onbekend Onbekend System.Array
ELEMENT_TYPE_SZARRAY Opgegeven op type. 1 0 type [ n ]

Onbeheerde matrices

Onbeheerde matrices zijn COM-stijl veilige matrices of C-achtige matrices met vaste of variabele lengte. Veilige matrices zijn zelfbeschrijfde matrices die het type, de rangschikking en de grenzen van de bijbehorende matrixgegevens bevatten. Matrices in C-stijl zijn eendimensionale getypeerde matrices met een vaste ondergrens van 0. De marshallservice biedt beperkte ondersteuning voor beide typen matrices.

Matrixparameters doorgeven aan .NET-code

Zowel C-achtige matrices als veilige matrices kunnen worden doorgegeven aan .NET-code vanuit onbeheerde code als een veilige matrix of een C-stijlmatrix. In de volgende tabel ziet u de waarde van het niet-beheerde type en het geïmporteerde type.

Niet-beheerd type Geïmporteerd type
SafeArray( Type ) < ELEMENT_TYPE_SZARRAY ConvertedType >

Rang = 1, ondergrens = 0. De grootte is alleen bekend als deze is opgegeven in de beheerde handtekening. Veilige matrices die niet rangschikken = 1 of ondergrens = 0 kunnen niet worden ge marshalld als SZARRAY.
Type [] < ELEMENT_TYPE_SZARRAY ConvertedType >

Rang = 1, ondergrens = 0. De grootte is alleen bekend als deze is opgegeven in de beheerde handtekening.

Veilige matrices

Wanneer een veilige matrix wordt geïmporteerd uit een typebibliotheek naar een .NET-assembly, wordt de matrix geconverteerd naar een eendimensionale matrix van een bekend type (zoals int). Dezelfde typeconversieregels die van toepassing zijn op parameters, zijn ook van toepassing op matrixelementen. Een veilige matrix van BSTR-typen wordt bijvoorbeeld een beheerde matrix met tekenreeksen en een veilige matrix met varianten wordt een beheerde matrix van objecten. Het elementtype SAFEARRAY wordt vastgelegd uit de typebibliotheek en opgeslagen in de SAFEARRAY-waarde van de UnmanagedType opsomming.

Omdat de positie en grenzen van de veilige matrix niet kunnen worden bepaald uit de typebibliotheek, wordt ervan uitgegaan dat de rang gelijk is aan 1 en de ondergrens wordt aangenomen op gelijk aan 0. De rang en grenzen moeten worden gedefinieerd in de beheerde handtekening die wordt geproduceerd door typebibliotheekimporteur (Tlbimp.exe). Als de rang die tijdens runtime aan de methode is doorgegeven, verschilt, wordt er een SafeArrayRankMismatchException gegenereerd. Als het type matrix dat tijdens de runtime is doorgegeven, verschilt, wordt er een SafeArrayTypeMismatchException gegenereerd. In het volgende voorbeeld ziet u veilige matrices in beheerde en onbeheerde code.

Onbeheerde handtekening

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

Beheerde handtekening

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);

Multidimensionale of niet-afhankelijke veilige matrices kunnen worden ingedeeld in beheerde code als de methodehandtekening die door Tlbimp.exe wordt geproduceerd, wordt gewijzigd om een elementtype van ELEMENT_TYPE_ARRAY aan te geven in plaats van ELEMENT_TYPE_SZARRAY. U kunt ook de schakeloptie /sysarray gebruiken met Tlbimp.exe om alle matrices als System.Array objecten te importeren. In gevallen waarin de doorgegeven matrix multidimensionaal is, kunt u de algemene tussentaalcode (CIL) bewerken die wordt geproduceerd door Tlbimp.exe en deze vervolgens opnieuw compileren. Zie Aanroepbare wrappers voor runtime aanpassen voor meer informatie over het wijzigen van CIL-code.

Matrices in C-stijl

Wanneer een C-stijlmatrix wordt geïmporteerd uit een typebibliotheek naar een .NET-assembly, wordt de matrix geconverteerd naar ELEMENT_TYPE_SZARRAY.

Het matrixelementtype wordt bepaald uit de typebibliotheek en behouden tijdens het importeren. Dezelfde conversieregels die van toepassing zijn op parameters, zijn ook van toepassing op matrixelementen. Een matrix met LPStr-typen wordt bijvoorbeeld een matrix van tekenreekstypen . Tlbimp.exe legt het type matrixelement vast en past het MarshalAsAttribute kenmerk toe op de parameter.

De matrixrang wordt verondersteld gelijk te zijn aan 1. Als de rangorde groter is dan 1, wordt de matrix ge marshalld als een eendimensionale matrix in kolom-primaire volgorde. De ondergrens is altijd gelijk aan 0.

Typebibliotheken kunnen matrices met een vaste of variabele lengte bevatten. Tlbimp.exe kan alleen matrices met een vaste lengte importeren uit typebibliotheken, omdat typebibliotheken niet beschikken over de informatie die nodig is voor marshal variable-length matrices. Met matrices met een vaste lengte wordt de grootte geïmporteerd uit de typebibliotheek en vastgelegd in marshalAsAttribute die wordt toegepast op de parameter.

U moet handmatig typebibliotheken definiëren die matrices met een variabele lengte bevatten, zoals wordt weergegeven in het volgende voorbeeld.

Onbeheerde handtekening

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

Beheerde handtekening

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);

Hoewel u de kenmerken van de size_is of length_is kunt toepassen op een matrix in de IDL-bron (Interface Definition Language) om de grootte over te brengen naar een client, geeft de MIDL-compiler (Microsoft Interface Definition Language) die informatie niet door aan de typebibliotheek. Zonder de grootte te kennen, kan de interop marshalling-service de matrixelementen niet marshalen. Daarom worden matrices met variabele lengte geïmporteerd als referentieargumenten. Voorbeeld:

Onbeheerde handtekening

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

Beheerde handtekening

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);

U kunt de marshaller voorzien van de matrixgrootte door de algemene tussentaalcode (CIL) te bewerken die wordt geproduceerd door Tlbimp.exe en vervolgens opnieuw te compileren. Zie Aanroepbare wrappers voor runtime aanpassen voor meer informatie over het wijzigen van CIL-code. Als u het aantal elementen in de matrix wilt aangeven, past u het MarshalAsAttribute type toe op de matrixparameter van de definitie van de beheerde methode op een van de volgende manieren:

  • Identificeer een andere parameter die het aantal elementen in de matrix bevat. De parameters worden geïdentificeerd op positie, te beginnen met de eerste parameter als getal 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 );
    
  • Definieer de grootte van de matrix als een constante. Voorbeeld:

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

Bij het marshallen van matrices van niet-beheerde code naar beheerde code controleert de marshaller de MarshalAsAttribute die is gekoppeld aan de parameter om de grootte van de matrix te bepalen. Als de matrixgrootte niet is opgegeven, wordt slechts één element ge marshalld.

Notitie

MarshalAsAttribute heeft geen effect op het marshallen van beheerde matrices naar onbeheerde code. In die richting wordt de matrixgrootte bepaald door onderzoek. Er is geen manier om een subset van een beheerde matrix te marshalen.

De interop marshaller maakt gebruik van de Methoden CoTaskMemAlloc en CoTaskMemFree in Windows of malloc en gratis methoden op andere besturingssystemen om geheugen toe te wijzen en op te halen. Geheugentoewijzing die wordt uitgevoerd door niet-beheerde code, moet ook gebruikmaken van deze methoden.

Matrices doorgeven aan COM

Alle beheerde matrixtypen kunnen worden doorgegeven aan niet-beheerde code uit beheerde code. Afhankelijk van het beheerde type en de kenmerken die erop zijn toegepast, kan de matrix worden geopend als een veilige matrix of een C-stijlmatrix, zoals wordt weergegeven in de volgende tabel.

Beheerd matrixtype Geëxporteerd als
< ELEMENT_TYPE_SZARRAY type > UnmanagedType. SafeArray( type )

UnmanagedType.LPArray

Het type wordt opgegeven in de handtekening. Rang is altijd 1, ondergrens is altijd 0. Grootte is altijd bekend tijdens runtime.
< ELEMENT_TYPE_ARRAY type > < rang >[ < grenzen ] > UnmanagedType.SafeArray( type )

UnmanagedType.LPArray

Typ, rang, grenzen worden opgegeven in de handtekening. Grootte is altijd bekend tijdens runtime.
ELEMENT_TYPE_CLASS <System.Array> UT_Interface

UnmanagedType.SafeArray( type )

Type, rang, grenzen en grootte zijn altijd bekend tijdens runtime.

Er is een beperking in OLE Automation met betrekking tot matrices van structuren die LPSTR of LPWSTR bevatten. Daarom moeten tekenreeksvelden worden ge marshalld als UnmanagedType.BSTR. Anders wordt er een uitzondering gegenereerd.

ELEMENT_TYPE_SZARRAY

Wanneer een methode met een ELEMENT_TYPE_SZARRAY parameter (eendimensionale matrix) wordt geëxporteerd van een .NET-assembly naar een typebibliotheek, wordt de matrixparameter geconverteerd naar een SAFEARRAY van een bepaald type. Dezelfde conversieregels zijn van toepassing op de typen matrixelementen. De inhoud van de beheerde matrix wordt automatisch uit het beheerde geheugen gekopieerd naar de SAFEARRAY. Voorbeeld:

Beheerde handtekening

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

Onbeheerde handtekening

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

De positie van de veilige matrices is altijd 1 en de ondergrens is altijd 0. De grootte wordt tijdens runtime bepaald door de grootte van de beheerde matrix die wordt doorgegeven.

De matrix kan ook worden ge marshalld als een C-stijlmatrix met behulp van het MarshalAsAttribute kenmerk. Voorbeeld:

Beheerde handtekening

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 );

Onbeheerde handtekening

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

Hoewel de marshaller de lengtegegevens heeft die nodig zijn om de matrix te marshalen, wordt de matrixlengte meestal doorgegeven als een afzonderlijk argument om de lengte over te brengen aan de aanwijzer.

ELEMENT_TYPE_ARRAY

Wanneer een methode met een ELEMENT_TYPE_ARRAY parameter wordt geëxporteerd van een .NET-assembly naar een typebibliotheek, wordt de matrixparameter geconverteerd naar een SAFEARRAY van een bepaald type. De inhoud van de beheerde matrix wordt automatisch uit het beheerde geheugen gekopieerd naar de SAFEARRAY. Voorbeeld:

Beheerde handtekening

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

Onbeheerde handtekening

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

De positie, grootte en grenzen van de veilige matrices worden tijdens runtime bepaald door de kenmerken van de beheerde matrix.

De matrix kan ook worden ge marshalld als een C-stijlmatrix door het MarshalAsAttribute kenmerk toe te passen. Voorbeeld:

Beheerde handtekening

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 );

Onbeheerde handtekening

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

Geneste matrices kunnen niet worden ge marshalld. Met de volgende handtekening wordt bijvoorbeeld een fout gegenereerd bij het exporteren met de typebibliotheekexporteur (Tlbexp.exe).

Beheerde handtekening

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

<ELEMENT_TYPE_CLASS System.Array>

Wanneer een methode met een System.Array parameter wordt geëxporteerd van een .NET-assembly naar een typebibliotheek, wordt de matrixparameter geconverteerd naar een _Array interface. De inhoud van de beheerde matrix is alleen toegankelijk via de methoden en eigenschappen van de _Array-interface . System.Array kan ook worden ge marshalld als een SAFEARRAY met behulp van het MarshalAsAttribute kenmerk. Wanneer marshalling als een veilige matrix wordt gebruikt, worden de matrixelementen als varianten ge marshalld. Voorbeeld:

Beheerde handtekening

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 );

Onbeheerde handtekening

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

Matrices binnen structuren

Onbeheerde structuren kunnen ingesloten matrices bevatten. Deze ingesloten matrixvelden worden standaard marshalled als een SAFEARRAY. In het volgende voorbeeld s1 is een ingesloten matrix die rechtstreeks in de structuur zelf wordt toegewezen.

Onbeheerde weergave

struct MyStruct {
    short s1[128];
}

Matrices kunnen worden ge marshalld als UnmanagedType, waarvoor u het MarshalAsAttribute veld moet instellen. De grootte kan alleen worden ingesteld als een constante. De volgende code toont de bijbehorende beheerde definitie van 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;
}

Zie ook