Sdílet prostřednictvím


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

Viz také