Dela via


Anpassade marshallerformer

Den här artikeln beskriver de olika "strukturerna" för anpassade marshallers som kan användas med .NET interop-källkodsgeneratorn.

Värdeomvandlare

I det här avsnittet beskrivs formerna för anpassade marshallers som kan användas av .NET interop-källgeneratorn för att samla värdetyper mellan hanterad och ohanterad kod.

Tillståndslös hanterad till ohanterad

Med den här formen anropar ConvertToUnmanaged den genererade koden för att konvertera ett värde till intern kod, eller GetPinnableReference när det är tillämpligt. Den genererade koden anropar Free när det är tillämpligt för att låta marshallaren frigöra ohanterade resurser som är associerade med den hanterade typen när dess livslängd är slut.

[CustomMarshaller(typeof(TManaged), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
[CustomMarshaller(typeof(TManaged), MarshalMode.UnmanagedToManagedOut, typeof(ManagedToNative))]
static class TMarshaller
{
    public static class ManagedToNative
    {
        /// <summary>
        /// Converts a managed type to an unmanaged representation. May throw exceptions.
        /// </summary>
        public static TNative ConvertToUnmanaged(TManaged managed);

        /// <summary>
        /// Optional.
        /// Returns a pinnable reference to the unmanaged representation.
        /// The reference will be pinned and passed as a pointer to the native code.
        /// TOther should be a dereferenced type of TNative.
        /// For example, if TNative is `int*`, then TOther should be `int`.
        /// </summary>
        public static ref TNativeDereferenced GetPinnableReference(TManaged managed);

        /// <summary>
        /// Optional.
        /// Frees any unmanaged resources associated with the marshalling of the managed type.
        /// Must not throw exceptions.
        /// </summary>
        public static void Free(TNative unmanaged);
    }
}

Tillståndslös hanterad till ohanterad med anroparens allokerade buffert

Med den här formen allokerar generatorn en buffert av den angivna storleken och skickar den ConvertToUnmanaged till metoden för att konvertera ett värde till intern kod. Den genererade koden hanterar livslängden för den här bufferten.

[CustomMarshaller(typeof(TManaged), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
[CustomMarshaller(typeof(TManaged), MarshalMode.UnmanagedToManagedOut, typeof(ManagedToNative))]
static class TMarshaller
{
    public static class ManagedToNative
    {
        /// <summary>
        /// The size of the buffer that will be allocated by the generator.
        /// </summary>
        public static int BufferSize { get; }

        /// <summary>
        /// Converts a managed type to an unmanaged representation using a caller-allocated buffer.
        /// </summary>
        public static TNative ConvertToUnmanaged(TManaged managed, Span<byte> callerAllocatedBuffer);

        /// <summary>
        /// Optional.
        /// Frees any unmanaged resources associated with the marshalling of the managed type.
        /// Must not throw exceptions.
        /// </summary>
        public static void Free(TNative unmanaged);
    }
}

Tillståndslös från ohanterad till hanterad

[CustomMarshaller(typeof(TManaged), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
[CustomMarshaller(typeof(TManaged), MarshalMode.UnmanagedToManagedIn, typeof(NativeToManaged))]
static class TMarshaller
{
    public static class NativeToManaged
    {
        /// <summary>
        /// Converts an unmanaged representation to a managed type. May throw exceptions.
        /// </summary>
        public static TManaged ConvertToManaged(TNative unmanaged);

        /// <summary>
        /// Optional.
        /// Frees any unmanaged resources associated with the marshalling of the managed type.
        /// Must not throw exceptions.
        /// </summary>
        public static void Free(TNative unmanaged);
    }
}

Tillståndslös icke-hanterad till hanterad med garanterad avmarshalling

Den här strukturen instruerar generatorn att generera kod för unmarshaling på ett sätt som garanterar att unmarshaling kommer att anropas, även om en tidigare marshaller kastar ett undantag. Detta är användbart för typer som måste rensas eller slutföras oavsett om de tidigare åtgärderna lyckades.

[CustomMarshaller(typeof(TManaged), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
[CustomMarshaller(typeof(TManaged), MarshalMode.UnmanagedToManagedIn, typeof(NativeToManaged))]
static class TMarshaller
{
    public static class NativeToManaged
    {
        /// <summary>
        /// Converts an unmanaged representation to a managed type.
        /// Should not throw exceptions.
        /// </summary>
        public static TManaged ConvertToManagedFinally(TNative unmanaged);

        /// <summary>
        /// Optional.
        /// Frees any unmanaged resources associated with the marshalling of the managed type.
        /// Must not throw exceptions.
        /// </summary>
        public static void Free(TNative unmanaged);
    }
}

Tillståndslös dubbelriktad

Med den här formen kan hanterade till ohanterade samt ohanterade till hanterade konverteringar göras, där marshallern är tillståndslös. Generatorn kommer att använda metoden ConvertToUnmanaged för konvertering från hanterade till ohanterade och metoden ConvertToManaged för konvertering från ohanterade till hanterade.

[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.ManagedToUnmanagedRef, typeof(Bidirectional))]
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.UnmanagedToManagedRef, typeof(Bidirectional))]
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.ElementRef, typeof(Bidirectional))]
static class TMarshaller<T, U, V...>
{
    public static class Bidirectional
    {
        // Include members from each of the following:
        // - One Stateless Managed->Unmanaged Value shape
        // - One Stateless Unmanaged->Managed Value shape
    }
}

Tillståndsbevarande från hanterat till ohanterat

Den här formen möjliggör tillståndskänslig dataöverföring från hanterad till ohanterad. Den genererade koden kommer att använda en unik marshallerinstans för varje parameter, så att marshallerinstansen kan behålla tillstånd under marshalling.

[CustomMarshaller(typeof(TManaged), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
[CustomMarshaller(typeof(TManaged), MarshalMode.UnmanagedToManagedOut, typeof(ManagedToNative))]
static class TMarshaller
{
    public struct ManagedToNative // Can be ref struct
    {
        /// <summary>
        /// Optional constructor.
        /// May throw exceptions.
        /// </summary>
        public ManagedToNative();

        /// <summary>
        /// Takes a managed type to be converted to an unmanaged representation in ToUnmanaged or GetPinnableReference.
        /// </summary>
        public void FromManaged(TManaged managed);

        /// <summary>
        /// Optional.
        /// Returns a pinnable reference to the unmanaged representation.
        /// The reference will be pinned and passed as a pointer to the native code.
        /// TOther should be a dereferenced type of TNative.
        /// For example, if TNative is `int*`, then TOther should be `int`.
        /// When applicable, this method is preferred to ToUnmanaged for marshalling.
        /// </summary>
        public ref TIgnored GetPinnableReference();

        /// <summary>
        /// Optional.
        /// Returns a pinnable reference to the unmanaged representation.
        /// The reference will be pinned and passed as a pointer to the native code.
        /// TOther should be a dereferenced type of TNative.
        /// For example, if TNative is `int*`, then TOther should be `int`.
        /// When applicable, only this method is called for the marshalling step.
        /// May throw exceptions.
        /// </summary>
        public static ref TOther GetPinnableReference(TManaged managed);

        /// <summary>
        /// Converts the managed type to an unmanaged representation.
        /// May throw exceptions.
        /// </summary>
        public TNative ToUnmanaged();

        /// <summary>
        /// Optional.
        /// In managed to unmanaged stubs, this method is called after call to the unmanaged code.
        /// Must not throw exceptions.
        /// </summary>
        public void OnInvoked();

        /// <summary>
        /// Optional.
        /// Frees any unmanaged resources associated with the marshalling of the managed type.
        /// Must not throw exceptions.
        /// </summary>
        public void Free();
    }
}

Tillståndsbevarande från hanterad kod till ohanterad kod med buffert allokerad av anroparen.

Den här formen möjliggör tillståndskänslig marshalling från hanterad miljö till ohanterad miljö, där generatorn allokerar en buffert av den angivna storleken och skickar den till FromManaged metoden. Den genererade koden använder en unik marshallerinstans för varje parameter, så att marshallern kan underhålla tillstånd genom marshalleringsprocessen.

[CustomMarshaller(typeof(TManaged), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
[CustomMarshaller(typeof(TManaged), MarshalMode.UnmanagedToManagedOut, typeof(ManagedToNative))]
static class TMarshaller
{
    public struct ManagedToNative // Can be ref struct
    {
        /// <summary>
        /// The length of the buffer that will be allocated by the generator.
        /// </summary>
        public static int BufferSize { get; }

        /// <summary>
        /// Optional constructor.
        /// May throw exceptions.
        /// </summary>
        public ManagedToNative();

        /// <summary>
        /// Takes a managed type to be converted to an unmanaged representation in ToUnmanaged or GetPinnableReference.
        /// May throw exceptions.
        /// </summary>
        public void FromManaged(TManaged managed, Span<TBuffer> buffer);

        /// <summary>
        /// Optional.
        /// Returns a pinnable reference to the unmanaged representation.
        /// The reference will be pinned and passed as a pointer to the native code.
        /// TOther should be a dereferenced type of TNative.
        /// For example, if TNative is `int*`, then TOther should be `int`.
        /// When applicable, this method is preferred to ToUnmanaged for marshalling.
        /// </summary>
        public ref TIgnored GetPinnableReference();

        /// <summary>
        /// Optional.
        /// Returns a pinnable reference to the unmanaged representation.
        /// The reference will be pinned and passed as a pointer to the native code.
        /// TOther should be a dereferenced type of TNative.
        /// For example, if TNative is `int*`, then TOther should be `int`.
        /// When applicable, only this method is called for the marshalling step.
        /// May throw exceptions.
        public static ref TOther GetPinnableReference(TManaged managed);

        /// <summary>
        /// Returns the unmanaged representation of the managed value.
        /// May throw exceptions.
        /// </summary>
        public TNative ToUnmanaged();

        /// <summary>
        /// Optional.
        /// In managed to unmanaged stubs, this method is called after call to the unmanaged code.
        /// Must not throw exceptions.
        /// </summary>
        public void OnInvoked();

        /// <summary>
        /// Optional.
        /// Frees any unmanaged resources associated with the marshalling of the managed type.
        /// Must not throw exceptions.
        /// </summary>
        public void Free();
    }
}

Tillståndsbevarande ohanterad till hanterad

Den här strukturen möjliggör tillståndskänslig omarshalling från ohanterad till hanterad kod. Den genererade koden använder en unik instans för varje parameter, så att structen kan bevara sitt tillstånd under avmatrisering.

[CustomMarshaller(typeof(TManaged), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
[CustomMarshaller(typeof(TManaged), MarshalMode.UnmanagedToManagedIn, typeof(NativeToManaged))]
static class TMarshaller
{
    public struct NativeToManaged // Can be ref struct
    {
        /// <summary>
        /// Optional constructor.
        /// May throw exceptions.
        /// </summary>
        public NativeToManaged();

        /// <summary>
        /// Takes an unmanaged representation to be converted to a managed type in ToManaged.
        /// Should not throw exceptions.
        /// </summary>
        public void FromUnmanaged(TNative unmanaged);

        /// <summary>
        /// Returns the managed value representation of the unmanaged value.
        /// May throw exceptions.
        /// </summary>
        public TManaged ToManaged();

        /// <summary>
        /// Optional.
        /// Frees any unmanaged resources associated with the unmarshalling of the managed type.
        /// Must not throw exceptions.
        /// </summary>
        public void Free();
    }
}

Tillståndsfull från icke-hanterad till hanterad med garanterad omstrukturering

Den här formen möjliggör tillståndskänslig omarshalling från ohanterad till hanterad, med generatorn ToManagedFinally som säkerställer att metoden anropas även om en tidigare marshaller genererar ett undantag. Detta är användbart för typer som måste rensas eller slutföras oavsett om de tidigare åtgärderna lyckades.

[CustomMarshaller(typeof(TManaged), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
[CustomMarshaller(typeof(TManaged), MarshalMode.UnmanagedToManagedIn, typeof(NativeToManaged))]
static class TMarshaller
{
    public struct NativeToManaged // Can be ref struct
    {
        /// <summary>
        /// Optional constructor.
        /// May throw exceptions.
        /// </summary>
        public NativeToManaged();

        /// <summary>
        /// Takes an unmanaged representation to be converted to a managed type in ToManagedFinally.
        /// Should not throw exceptions.
        /// </summary>
        public void FromUnmanaged(TNative unmanaged);

        /// <summary>
        /// Returns the managed value representation of the unmanaged value.
        /// Should not throw exceptions.
        /// </summary>
        public TManaged ToManagedFinally();

        /// <summary>
        /// Optional.
        /// Frees any unmanaged resources associated with the unmarshalling of the managed type.
        /// Must not throw exceptions.
        /// </summary>
        public void Free();
    }
}

Tillståndskänslig dubbelriktad

[CustomMarshaller(typeof(TManaged), MarshalMode.ManagedToUnmanagedRef, typeof(Bidirectional))]
[CustomMarshaller(typeof(TManaged), MarshalMode.UnmanagedToManagedRef, typeof(Bidirectional))]
static class TMarshaller
{
    public struct Bidirectional // Can be ref struct
    {
        // Include members from each of the following:
        // - One Stateful Managed->Unmanaged Value shape
        // - One Stateful Unmanaged->Managed Value shape
    }
}

Samlingmarshallers

I det här avsnittet beskrivs former för anpassade samlingsmarshallers som .NET interop-källkodgeneratorn stöder för att marshalla samlingar mellan hanterad och ohanterad kod. Sammanhängande samlingsmarshalls används för samlingar som representeras som ett sammanhängande minnesblock i sin ohanterade representation, till exempel matriser eller listor.

När samlingstypen som överförs i minne är generisk över sin elementtyp (till exempel List<T>), har den anpassade typen av minnesöverföring vanligtvis två generiska parametrar: en för den hanterade elementtypen och en för den ohanterade elementtypen. I fall där samlingen inte är generisk över dess elementtyp (till exempel StringCollection), kanske marshaller bara har en enda generisk parameter för den ohanterade elementtypen. Exempel på marshallerstruktur visar en marshaller för en icke-generisk samling TCollection med element av typen TManagedElement. Eftersom elementen kan marshallas med olika värde-marshallers måste de vara generiska över den ohanterade elementtypen TUnmanagedElement. Den interna representationen av samlingen anropas TNative (vanligtvis är det *TUnmanagedElement).

Overgång från tillståndslöst hanterat till ohanterat

Med den här formen använder generatorn statiska metoder för att konvertera en hanterad samling till ohanterat minne. Marshaller måste tillhandahålla metoder för att allokera den ohanterade containern, komma åt hanterade och ohanterade element och eventuellt frigöra ohanterade resurser.

[CustomMarshaller(typeof(TCollection), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
[CustomMarshaller(typeof(TCollection), MarshalMode.UnmanagedToManagedOut, typeof(ManagedToNative))]
[CustomMarshaller(typeof(TCollection), MarshalMode.ElementIn, typeof(ManagedToNative))]
[ContiguousCollectionMarshaller]
static class TMarshaller<TUnmanagedElement> where TUnmanagedElement : unmanaged
{
    public static class ManagedToNative
    {
        /// <summary>
        /// Gets the uninitialized unmanaged container for the elements and assigns the number of elements to numElements.
        /// The return value is later passed to GetUnmanagedValuesDestination.
        /// </summary>
        public static TNative AllocateContainerForUnmanagedElements(TCollection managed, out int numElements);

        /// <summary>
        /// Gets a span of managed elements in the collection.
        /// The elements in this span are marshalled by the element marshaller and put into the unmanaged container.
        /// </summary>
        public static ReadOnlySpan<TManagedElement> GetManagedValuesSource(TCollection managed);

        /// <summary>
        /// Gets a span of unmanaged elements from the TNative container.
        /// The elements in this span are filled with the marshalled values from the managed collection.
        /// </summary>
        public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(TNative unmanaged, int numElements);

        /// <summary>
        /// Optional. Returns a pinnable reference to the unmanaged representations of the elements.
        /// TOther should be a dereferenced type of TNative.
        /// For example, if TNative is `int*`, then TOther should be `int`.
        /// </summary>
        public static ref TOther GetPinnableReference(TManaged managed);

        /// <summary>
        /// Optional. Frees unmanaged resources.
        /// Should not throw exceptions.
        /// </summary>
        public static void Free(TNative unmanaged);
    }
}

Tillståndslös hanterad till ohanterad med anroparens allokerade buffert

Generatorn allokerar en buffert och skickar den till marshaller för användning under marshalling.

[CustomMarshaller(typeof(TCollection), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
[CustomMarshaller(typeof(TCollection), MarshalMode.ElementIn, typeof(ManagedToNative))]
[ContiguousCollectionMarshaller]
static class TMarshaller<TUnmanagedElement> where TUnmanagedElement : unmanaged
{
    public static class ManagedToNative
    {
        /// <summary>
        /// The length of the buffer that will be allocated by the generated code and passed to AllocateContainerForUnmanagedElements.
        /// </summary>
        public static int BufferSize { get; }

        /// <summary>
        /// Creates the unmanaged container using a caller-allocated buffer, and assigns the number of elements in the collection to numElements.
        /// The return value is later passed to GetUnmanagedValuesDestination.
        /// </summary>
        public static TNative AllocateContainerForUnmanagedElements(TCollection managed, Span<TBuffer> buffer, out int numElements);

        /// <summary>
        /// Gets a span of managed elements in the collection.
        /// The elements in this span are marshalled by the element marshaller and put into the unmanaged container.
        /// </summary>
        public static ReadOnlySpan<TManagedElement> GetManagedValuesSource(TCollection managed);

        /// <summary>
        /// Gets a span of unmanaged elements from the TNative container.
        /// The elements in this span are filled with the marshalled values from the managed collection.
        /// </summary>
        public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(TNative unmanaged, int numElements);

        /// <summary>
        /// Optional. Returns a pinnable reference to the unmanaged representations of the elements.
        /// TOther should be a dereferenced type of TNative.
        /// For example, if TNative is `int*`, then TOther should be `int`.
        /// </summary>
        public static ref TOther GetPinnableReference(TManaged managed);

        /// <summary>
        /// Optional. Frees unmanaged resources.
        /// Should not throw exceptions.
        /// </summary>
        public static void Free(TNative unmanaged);
    }
}

Tillståndslös ohanterad till hanterad

Den här formen konverterar från ohanterat minne till en hanterad samling.

[CustomMarshaller(typeof(TCollection), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
[CustomMarshaller(typeof(TCollection), MarshalMode.UnmanagedToManagedIn, typeof(NativeToManaged))]
[CustomMarshaller(typeof(TCollection), MarshalMode.ElementOut, typeof(NativeToManaged))]
[ContiguousCollectionMarshaller]
static class TMarshaller<TUnmanagedElement> where TUnmanagedElement : unmanaged
{
    public static class NativeToManaged
    {
        /// <summary>
        /// Allocates a new collection for unmarshalling.
        /// May throw exceptions.
        /// </summary>
        public static TCollection AllocateContainerForManagedElements(TNative unmanaged, int numElements);

        /// <summary>
        /// Gets the destination span that unmarshalled managed elements will be written to.
        /// May throw exceptions.
        /// </summary>
        public static Span<TManagedElement> GetManagedValuesDestination(TCollection managed);

        /// <summary>
        /// Gets the source span of unmanaged elements to unmarshal from.
        /// May throw exceptions.
        /// </summary>
        public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(TNative unmanaged, int numElements);

        /// <summary>
        /// Optional. Frees unmanaged resources.
        /// Should not throw exceptions.
        /// </summary>
        public static void Free(TNative unmanaged);
    }
}

Tillståndslös ohanterad till hanterad med garanterad omarshalling

Generatorn säkerställer att omarshalling inträffar även om en tidigare marshaller utlöser ett undantag.

[CustomMarshaller(typeof(TCollection), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
[ContiguousCollectionMarshaller]
static class TMarshaller<TUnmanagedElement> where TUnmanagedElement : unmanaged
{
    public static class NativeToManaged
    {
        /// <summary>
        /// Allocates the managed container for the elements.
        /// Should not throw exceptions other than OutOfMemoryException.
        /// </summary>
        public static TCollection AllocateContainerForManagedElementsFinally(TNative unmanaged, int numElements);

        /// <summary>
        /// Gets the destination span that unmarshalled managed elements will be written to.
        /// May throw exceptions.
        /// </summary>
        public static Span<TManagedElement> GetManagedValuesDestination(TCollection managed);

        /// <summary>
        /// Gets the source span of unmanaged elements to unmarshal from.
        /// May throw exceptions.
        /// </summary>
        public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(TNative unmanaged, int numElements);

        /// <summary>
        /// Optional. Frees unmanaged resources.
        /// Should not throw exceptions.
        /// </summary>
        public static void Free(TNative unmanaged);
    }
}

Tillståndslös dubbelriktad

Den här formen stöder konverteringar från hanterade till ohanterade och från ohanterade till hanterade.

[CustomMarshaller(typeof(TCollection), MarshalMode.ManagedToUnmanagedRef, typeof(Bidirectional))]
[CustomMarshaller(typeof(TCollection), MarshalMode.UnmanagedToManagedRef, typeof(Bidirectional))]
[CustomMarshaller(typeof(TCollection), MarshalMode.ElementRef, typeof(Bidirectional))]
[ContiguousCollectionMarshaller]
static class TMarshaller<TUnmanagedElement> where TUnmanagedElement : unmanaged
{
    public static class Bidirectional
    {
        // Include members from each of the following:
        // - One Stateless Managed->Unmanaged Linear Collection shape
        // - One Stateless Unmanaged->Managed Linear Collection shape
    }
}

Tillståndsbevarande från hanterat till ohanterat

Den här formen gör att marshalen kan bevara tillstånd genom hela marshallingprocessen.

[CustomMarshaller(typeof(TCollection), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
[CustomMarshaller(typeof(TCollection), MarshalMode.UnmanagedToManagedOut, typeof(ManagedToNative))]
[ContiguousCollectionMarshaller]
static class TMarshaller<TUnmanagedElement> where TUnmanagedElement : unmanaged
{
    public struct ManagedToNative // Can be ref struct
    {
        /// <summary>
        /// Optional constructor.
        /// May throw exceptions.
        /// </summary>
        public ManagedToNative(); // Optional, can throw exceptions.

        /// <summary>
        /// Takes a managed collection to be converted to an unmanaged representation in ToUnmanaged or GetPinnableReference.
        /// </summary>
        public void FromManaged(TCollection collection); // Can throw exceptions.

        /// <summary>
        /// Gets the source span of managed elements to marshal.
        /// May throw exceptions.
        /// </summary>
        public ReadOnlySpan<TManagedElement> GetManagedValuesSource(); // Can throw exceptions.

        /// <summary>
        /// Gets the destination span of unmanaged elements to marshal to.
        /// May throw exceptions.
        /// </summary>
        public Span<TUnmanagedElement> GetUnmanagedValuesDestination(); // Can throw exceptions.

        /// <summary>
        /// Optional.
        /// Gets a pinnable reference to the unmanaged representation.
        /// The reference will be pinned and passed as a pointer to the native code.
        /// TOther should be a dereferenced type of TNative.
        /// For example, if TNative is `int*`, then TOther should be `int`.
        /// When applicable, this method is preferred to ToUnmanaged for marshalling.
        /// May throw exceptions.
        /// </summary>
        public ref TOther GetPinnableReference(); // Optional. Can throw exceptions.

        /// <summary>
        /// Optional.
        /// Gets a pinnable reference to the unmanaged representation.
        /// The reference will be pinned and passed as a pointer to the native code.
        /// TOther should be a dereferenced type of TNative.
        /// For example, if TNative is `int*`, then TOther should be `int`.
        /// When applicable, this method is preferred to the instance version and ToUnmanaged for marshalling.
        /// May throw exceptions.
        /// </summary>
        public static ref TOther GetPinnableReference(TCollection collection); // Optional. Can throw exceptions. Result pinnned and passed to Invoke.

        /// <summary>
        /// Converts the managed collection to an unmanaged representation.
        /// May throw exceptions.
        /// </summary>
        public TNative ToUnmanaged(); // Can throw exceptions.

        /// <summary>
        /// Optional.
        /// In managed to unmanaged stubs, this method is called after call to the unmanaged code.
        /// Must not throw exceptions.
        /// </summary>
        public void OnInvoked(); // Optional. Should not throw exceptions.
    }
}

Tillståndsbevarande från hanterad kod till ohanterad kod med buffert allokerad av anroparen.

[CustomMarshaller(typeof(TCollection), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
[ContiguousCollectionMarshaller]
static class TMarshaller<TUnmanagedElement> where TUnmanagedElement : unmanaged
{
    public struct ManagedToNative // Can be ref struct
    {
        /// <summary>
        /// The length of the buffer that will be allocated by the generated code and passed to FromManaged.
        /// </summary>
        public static int BufferSize { get; }

        /// <summary>
        /// Optional constructor.
        /// May throw exceptions.
        /// </summary>
        public ManagedToNative();

        /// <summary>
        /// Takes a managed collection to be converted to an unmanaged representation in ToUnmanaged or GetPinnableReference.
        /// The caller-allocated buffer is passed to this method.
        /// </summary>
        public void FromManaged(TCollection collection, Span<TBuffer> buffer);

        /// <summary>
        /// Gets the source span of managed elements to marshal.
        /// May throw exceptions.
        /// </summary>
        public ReadOnlySpan<TManagedElement> GetManagedValuesSource();

        /// <summary>
        /// Gets the destination span of unmanaged elements to marshal to.
        /// May throw exceptions.
        /// </summary>
        public Span<TUnmanagedElement> GetUnmanagedValuesDestination();

        /// <summary>
        /// Optional.
        /// Gets a pinnable reference to the unmanaged representation.
        /// The reference will be pinned and passed as a pointer to the native code.
        /// TOther should be a dereferenced type of TNative.
        /// For example, if TNative is `int*`, then TOther should be `int`.
        /// When applicable, this method is preferred to ToUnmanaged for marshalling.
        /// May throw exceptions.
        /// </summary>
        public ref TOther GetPinnableReference();

        /// <summary>
        /// Optional.
        /// Gets a pinnable reference to the unmanaged representation.
        /// The reference will be pinned and passed as a pointer to the native code.
        /// TOther should be a dereferenced type of TNative.
        /// For example, if TNative is `int*`, then TOther should be `int`.
        /// When applicable, this method is preferred to the instance GetPinnableReference and ToUnmanaged for marshalling.
        /// May throw exceptions.
        /// </summary>
        public static ref TOther GetPinnableReference(TCollection collection);

        /// <summary>
        /// Converts the managed collection to an unmanaged representation.
        /// May throw exceptions.
        /// </summary>
        public TNative ToUnmanaged();

        /// <summary>
        /// Optional.
        /// In managed to unmanaged stubs, this method is called after call to the unmanaged code.
        /// Must not throw exceptions.
        /// </summary>
        public void OnInvoked();
    }
}

Tillståndsbevarande ohanterad till hanterad

Den här formen gör det möjligt för marshaler att behålla tillstånd i avmarshallingprocessen.

[CustomMarshaller(typeof(TCollection), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
[CustomMarshaller(typeof(TCollection), MarshalMode.UnmanagedToManagedIn, typeof(NativeToManaged))]
[ContiguousCollectionMarshaller]
static class TMarshaller<TUnmanagedElement> where TUnmanagedElement : unmanaged
{
    public struct NativeToManaged // Can be ref struct
    {
        /// <summary>
        /// Optional constructor.
        /// May throw exceptions.
        /// </summary>
        public NativeToManaged();

        /// <summary>
        /// Takes an unmanaged collection to be converted to a managed representation in ToManaged.
        /// Should not throw exceptions.
        /// </summary>
        public void FromUnmanaged(TNative value);

        /// <summary>
        /// Gets the source span of unmanaged elements to unmarshal from.
        /// May throw exceptions.
        /// </summary>
        public ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(int numElements);

        /// <summary>
        /// Gets the destination span that unmarshalled managed elements will be written to.
        /// May throw exceptions.
        /// </summary>
        public Span<TManagedElement> GetManagedValuesDestination(int numElements);

        /// <summary>
        /// Returns the managed value representation of the unmanaged value.
        /// May throw exceptions.
        /// </summary>
        public TCollection ToManaged();

        /// <summary>
        /// Optional. Should not throw exceptions.
        /// </summary>
        public void Free();
    }
}

Tillståndsfull från icke-hanterad till hanterad med garanterad omstrukturering

[CustomMarshaller(typeof(TCollection), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
[ContiguousCollectionMarshaller]
static class TMarshaller<TUnmanagedElement> where TUnmanagedElement : unmanaged
{
    public struct NativeToManaged // Can be ref struct
    {
        /// <summary>
        /// Optional constructor.
        /// May throw exceptions.
        /// </summary>
        public NativeToManaged(); // Optional, can throw exceptions.

        /// <summary>
        /// Takes an unmanaged collection to be converted to a managed representation in ToManagedFinally.
        /// Should not throw exceptions.
        /// </summary>
        public void FromUnmanaged(TNative value);

        /// <summary>
        /// Gets the source span of unmanaged elements to unmarshal from.
        /// May throw exceptions.
        /// </summary>
        public ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(int numElements);

        /// <summary>
        /// Gets the destination span that unmarshalled managed elements will be written to.
        /// May throw exceptions.
        /// </summary>
        public Span<TManagedElement> GetManagedValuesDestination(int numElements);

        /// <summary>
        /// Returns the managed value representation of the unmanaged value.
        /// Should not throw exceptions.
        /// </summary>
        public TCollection ToManagedFinally();

        /// <summary>
        /// Optional. Should not throw exceptions.
        /// </summary>
        public void Free();
    }
}

Tillståndskänslig dubbelriktad

[CustomMarshaller(typeof(TCollection), MarshalMode.ManagedToUnmanagedRef, typeof(Bidirectional))]
[CustomMarshaller(typeof(TCollection), MarshalMode.UnmanagedToManagedRef, typeof(Bidirectional))]
[ContiguousCollectionMarshaller]
static class TMarshaller<TUnmanagedElement> where TUnmanagedElement : unmanaged
{
    public struct Bidirectional // Can be ref struct
    {
        // Include members from each of the following:
        // - One Stateful Managed->Unmanaged Contiguous Collection shape
        // - One Stateful Unmanaged->Managed Contiguous Collection shape
    }
}