Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Este artigo descreve as diferentes "formas" de marshallers personalizados que podem ser usados com o gerador de fonte de interoperabilidade .NET.
Organizadores de valor
Esta seção descreve as formas de marshallers personalizados que podem ser usadas pelo gerador de origem de interoperabilidade do .NET para organizar tipos de valor entre código gerenciado e não gerenciado.
Apátrida conseguiu não ser gerido
Com este formato, o código gerado chama ConvertToUnmanaged para converter um valor para código nativo, ou GetPinnableReference se aplicável. O código gerado chama Free quando aplicável para permitir que o marshaller libere quaisquer recursos não gerenciados associados ao tipo gerenciado quando sua vida útil terminar.
[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);
}
}
Stateless conseguiu não ser gerenciado com buffer alocado pelo chamador
Com este formato, o gerador alocará um buffer do tamanho especificado e o passará para o método ConvertToUnmanaged para transferir um valor para o código nativo. O código gerado lida com o tempo de vida desse buffer.
[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);
}
}
Apátrida não gerido
[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);
}
}
Sem estado não gerido para gerido com garantia de desmarshalling
Este formato instrui o gerador a emitir o código de desserialização, garantindo que a desserialização será chamada, mesmo que um serializador anterior lance uma exceção. Isso é útil para tipos que precisam ser limpos ou finalizados, independentemente do sucesso das operações anteriores.
[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);
}
}
Bidirecional apátrida
Esta forma permite conversões gerenciadas e não gerenciadas, com o marshaller sendo apátrida. O gerador usará o ConvertToUnmanaged método para conversões gerenciadas para não gerenciadas e o ConvertToManaged método para conversões não gerenciadas para gerenciadas.
[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
}
}
Stateful conseguiu não ser gerenciado
Esta forma permite o empacotamento stateful de gerenciado para não gerenciado. O código gerado usará uma instância exclusiva de marshaller para cada parâmetro, permitindo que o marshaller mantenha o seu estado durante todo o processo de 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();
}
}
Stateful conseguiu não ser gerenciado com buffer alocado pelo chamador
Esta forma permite o empacotamento stateful de gerenciado para não gerenciado, com o gerador alocando um buffer do tamanho especificado e passando-o para o FromManaged método. O código gerado usará uma instância de marshaller exclusiva para cada parâmetro, para que o marshaller possa manter o estado durante o processo de 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>
/// 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();
}
}
Stateful não gerenciado para gerenciar
Esta forma permite a desserialização com estado de não gerenciado para gerenciado. O código gerado usará uma instância exclusiva para cada parâmetro, para que a struct possa manter o estado durante o unmarshalling.
[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();
}
}
De não-gerido com estado para gerido com desmarshalling garantido
Esta forma permite o desempacotamento com estado de não-gerido para gerido, com o gerador garantindo que o método ToManagedFinally seja chamado mesmo se um marshaller anterior lançar uma exceção. Isso é útil para tipos que precisam ser limpos ou finalizados, independentemente do sucesso das operações anteriores.
[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();
}
}
Comunicação bidirecional com estado
[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
}
}
Marshalizadores de coleção
Esta seção descreve as formas de marshallers de coleção personalizados que o gerador de código-fonte de interoperabilidade .NET suporta para organizar coleções entre código gerenciado e não gerenciado. Os marshallers de coleção contíguos são usados para coleções que são representadas como um bloco contíguo de memória em sua representação não gerenciada, como matrizes ou listas.
Quando o tipo de coleção que está sendo empacotado é um genérico sobre seu tipo de elemento (por exemplo, List<T>), o tipo de marshaller personalizado normalmente terá dois parâmetros genéricos: um para o tipo de elemento gerenciado e outro para o tipo de elemento não gerenciado. Nos casos em que a coleção não é genérica sobre seu tipo de elemento (por exemplo, StringCollection), o marshaller pode ter apenas um único parâmetro genérico para o tipo de elemento não gerenciado. Os exemplos de forma de marshaller demonstram um marshaller para uma coleção TCollection não genérica com elementos do tipo TManagedElement. Uma vez que os elementos podem ser agrupados usando marshallers de valor diferente, ele deve ser genérico sobre o tipo de elemento não gerenciado, TUnmanagedElement. A representação nativa da coleção é chamada TNative (normalmente é *TUnmanagedElement).
Apátrida conseguiu não ser gerido
Nesta configuração, o gerador utiliza métodos estáticos para transferir uma coleção gerida para a memória não gerida. O marshaller deve fornecer métodos para alocar o contêiner não gerenciado, acessar elementos gerenciados e não gerenciados e, opcionalmente, liberar recursos não gerenciados.
[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);
}
}
Stateless conseguiu não ser gerenciado com buffer alocado pelo chamador
O gerador aloca uma memória intermédia e passa-a para o marshaller para ser utilizada durante o 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);
}
}
Apátrida não gerido
Essa forma passa da memória não gerenciada para uma coleção gerenciada.
[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);
}
}
Sem estado não gerido para gerido com garantia de des-serialização
O gerador assegura que o desempacotamento seja realizado mesmo que um marshaller anterior lance uma exceção.
[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);
}
}
Bidirecional sem estado
Esta forma oferece suporte a conversões entre ambientes geridos e não geridos.
[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
}
}
Stateful conseguiu não ser gerenciado
Esta forma permite que o marshaller mantenha o estado durante todo o processo de triagem.
[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.
}
}
Stateful conseguiu não ser gerenciado com buffer alocado pelo chamador
[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();
}
}
Stateful de não gerenciado para gerenciado
Esta forma permite que o marshaller mantenha o estado durante todo o processo de desempacotamento.
[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();
}
}
Stateful não-gerido para gerido com garantia de desserialização
[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();
}
}
Bidirecional Estado
[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
}
}