Generování zdrojů pro vlastní zařazování
.NET 7 zavádí nový mechanismus přizpůsobení způsobu řazení typu při použití zprostředkovatele generovaného zdrojem. Zdrojový generátor pro volání nespravovaných kódů rozpozná a NativeMarshallingAttribute jako indikátory MarshalUsingAttribute pro vlastní zařazování typu.
NativeMarshallingAttribute lze použít u typu, který označuje výchozí vlastní zařazování pro daný typ. Lze MarshalUsingAttribute použít u parametru nebo návratové hodnoty, aby bylo možné určit vlastní zařazování pro konkrétní použití typu, přičemž má přednost před libovolným NativeMarshallingAttribute typem, který může být na samotném typu. Oba tyto atributy očekávají Typetyp marshalleru vstupního bodu, který je označen jedním nebo více CustomMarshallerAttribute atributy. Každá CustomMarshallerAttribute označuje, která implementace marshalleru by měla být použita k zařazování zadaného spravovaného typu pro zadané MarshalMode.
Implementace Marshalleru
Implementace Marshalleru můžou být bezstavové nebo stavové. Pokud je typ marshalleru static
třída, považuje se za bezstavovou. Pokud se jedná o typ hodnoty, považuje se za stavový a jedna instance tohoto marshalleru se použije k zařazování konkrétního parametru nebo návratové hodnoty. Různé obrazce implementace marshalleru se očekávají na základě toho, jestli je marshaller bezstavový nebo stavový a jestli podporuje sesazování ze správy do nespravovaného, nespravovaného nebo obojího. Sada .NET SDK obsahuje analyzátory a opravy kódu, které pomáhají s implementací zařazovačů, které odpovídají požadovaným obrazcům.
MarshalMode
Zadaný MarshalMode v sadě CustomMarshallerAttribute určuje očekávanou podporu a tvar zařazování pro implementaci marshalleru. Všechny režimy podporují bezstavové implementace marshalleru. Režimy zařazování prvků nepodporují implementace stavových marshallerů.
MarshalMode |
Očekávaná podpora | Může být stavový |
---|---|---|
ManagedToUnmanagedIn | Spravováno s nespravovanými | Ano |
ManagedToUnmanagedRef | Spravované s nespravovanými a nespravovanými pro správu | Ano |
ManagedToUnmanagedOut | Nespravované spravované | Ano |
UnmanagedToManagedIn | Nespravované spravované | Ano |
UnmanagedToManagedRef | Spravované s nespravovanými a nespravovanými pro správu | Ano |
UnmanagedToManagedOut | Spravováno s nespravovanými | Ano |
ElementIn | Spravováno s nespravovanými | No |
ElementRef | Spravované s nespravovanými a nespravovanými pro správu | No |
ElementOut | Nespravované spravované | No |
MarshalMode.Default označuje, že implementace marshalleru by měla být použita pro jakýkoli režim, který podporuje. Pokud je zadána také implementace marshalleru pro konkrétnější MarshalMode
, má přednost před MarshalMode.Default
.
Základní použití
Můžeme zadat NativeMarshallingAttribute typ, který ukazuje na typ marshaller vstupního bodu, který je static
buď třída, nebo .struct
[NativeMarshalling(typeof(ExampleMarshaller))]
public struct Example
{
public string Message;
public int Flags;
}
ExampleMarshaller
, typ zařazovač vstupního bodu je označen značkou CustomMarshallerAttribute, odkazující na typ implementace marshalleru. V tomto příkladu ExampleMarshaller
je vstupním bodem i implementací. Odpovídá očekávaným obrazcům marshalleru pro vlastní zařazování hodnoty.
[CustomMarshaller(typeof(Example), MarshalMode.Default, typeof(ExampleMarshaller))]
internal static class ExampleMarshaller
{
public static ExampleUnmanaged ConvertToUnmanaged(Example managed)
=> throw new NotImplementedException();
public static Example ConvertToManaged(ExampleUnmanaged unmanaged)
=> throw new NotImplementedException();
public static void Free(ExampleUnmanaged unmanaged)
=> throw new NotImplementedException();
internal struct ExampleUnmanaged
{
public IntPtr Message;
public int Flags;
}
}
V ExampleMarshaller
příkladu je bezstavový marshaller, který implementuje podporu pro sesazování ze spravovaného do nespravovaného a nespravovaného do spravovaného. Logika zařazování je zcela řízena implementací marshalleru. Označení polí ve struktuře MarshalAsAttribute nemá žádný vliv na vygenerovaný kód.
Typ Example
se pak dá použít v generování zdroje volání nespravovaného kódu. V následujícím příkladu ExampleMarshaller
volání nespravovaného kódu se použije k zařazování parametru ze spravovaného na nespravované. Použije se také k zařazování návratové hodnoty z nespravované do spravované.
[LibraryImport("nativelib")]
internal static partial Example ConvertExample(Example example);
Pokud chcete pro konkrétní použití Example
typu použít jiný marshaller, zadejte MarshalUsingAttribute v lokalitě použití. V následujícím příkladu ExampleMarshaller
volání nespravovaného kódu se použije k zařazování parametru ze spravovaného na nespravované. OtherExampleMarshaller
se použije k zařazování návratové hodnoty z nespravované do spravované.
[LibraryImport("nativelib")]
[return: MarshalUsing(typeof(OtherExampleMarshaller))]
internal static partial Example ConvertExample(Example example);
Kolekce
ContiguousCollectionMarshallerAttribute Použijte typ vstupního bodu marshalleru, který označuje, že se jedná o souvislé kolekce. Typ musí mít více parametrů typu, než je přidružený spravovaný typ. Poslední parametr typu je zástupný symbol a zdrojový generátor vyplní nespravovaným typem pro typ elementu kolekce.
Můžete například zadat vlastní zařazování pro .List<T> V následujícím kódu ListMarshaller
je vstupním bodem i implementací. Odpovídá obrazcům marshalleru očekávaným pro vlastní zařazování kolekce.
[ContiguousCollectionMarshaller]
[CustomMarshaller(typeof(List<>), MarshalMode.Default, typeof(ListMarshaller<,>))]
public unsafe static class ListMarshaller<T, TUnmanagedElement> where TUnmanagedElement : unmanaged
{
public static byte* AllocateContainerForUnmanagedElements(List<T> managed, out int numElements)
=> throw new NotImplementedException();
public static ReadOnlySpan<T> GetManagedValuesSource(List<T> managed)
=> throw new NotImplementedException();
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(byte* unmanaged, int numElements)
=> throw new NotImplementedException();
public static List<T> AllocateContainerForManagedElements(byte* unmanaged, int length)
=> throw new NotImplementedException();
public static Span<T> GetManagedValuesDestination(List<T> managed)
=> throw new NotImplementedException();
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(byte* nativeValue, int numElements)
=> throw new NotImplementedException();
public static void Free(byte* unmanaged)
=> throw new NotImplementedException();
}
V ListMarshaller
příkladu je bezstavový zařazovač kolekce, který implementuje podporu pro sesazování ze spravovaného do nespravovaného a nespravovaného pro správu .List<T> V následujícím příkladu ListMarshaller
volání nespravovaného kódu se použije k zařazování parametru ze spravovaného do nespravovaného objektu a k zařazování návratové hodnoty z nespravované do spravované. CountElementName označuje, že numValues
parametr by měl být použit jako počet prvků při zařazování návratové hodnoty z nespravované do spravované.
[LibraryImport("nativelib")]
[return: MarshalUsing(typeof(ListMarshaller<,>), CountElementName = "numValues")]
internal static partial void ConvertList(
[MarshalUsing(typeof(ListMarshaller<,>))] List<int> list,
out int numValues);