Declaração fixed baseada em padrãoPattern-based fixed statement

ResumoSummary

Introduza um padrão que permitiria que os tipos participem de instruções fixed.Introduce a pattern that would allow types to participate in fixed statements.

MotivaçãoMotivation

O idioma fornece um mecanismo para fixar dados gerenciados e obter um ponteiro nativo para o buffer subjacente.The language provides a mechanism for pinning managed data and obtain a native pointer to the underlying buffer.

fixed(byte* ptr = byteArray)
{
   // ptr is a native pointer to the first element of the array
   // byteArray is protected from being moved/collected by the GC for the duration of this block 
}

O conjunto de tipos que podem participar de fixed é codificado e limitado a matrizes e System.String.The set of types that can participate in fixed is hardcoded and limited to arrays and System.String. O código de tipos "especiais" não é dimensionado quando novos primitivos, como ImmutableArray<T>, Span<T>``Utf8String são introduzidos.Hardcoding "special" types does not scale when new primitives such as ImmutableArray<T>, Span<T>, Utf8String are introduced.

Além disso, a solução atual para System.String se baseia em uma API razoavelmente rígida.In addition, the current solution for System.String relies on a fairly rigid API. A forma da API implica que System.String é um objeto contíguo que incorpora dados codificados UTF16 em um deslocamento fixo do cabeçalho do objeto.The shape of the API implies that System.String is a contiguous object that embeds UTF16 encoded data at a fixed offset from the object header. Essa abordagem foi encontrada com problemas em várias propostas que poderiam exigir alterações no layout subjacente.Such approach has been found problematic in several proposals that could require changes to the underlying layout. Seria desejável poder mudar para algo mais flexível que desassocie System.String objeto da sua representação interna para fins de interoperabilidade não gerenciada.It would be desirable to be able to switch to something more flexible that decouples System.String object from its internal representation for the purpose of unmanaged interop.

Design detalhadoDetailed design

PadrãoPattern

Uma "fixa" com base em padrões viável precisa:A viable pattern-based “fixed” need to:

  • Forneça as referências gerenciadas para fixar a instância e inicializar o ponteiro (preferivelmente esta é a mesma referência)Provide the managed references to pin the instance and to initialize the pointer (preferably this is the same reference)
  • Transmita sem ambigüidade o tipo do elemento não gerenciado (ou seja, "char" para "String")Convey unambiguously the type of the unmanaged element (i.e. “char” for “string”)
  • Prescrever o comportamento no caso "Empty" quando não houver nada para fazer referência a ele.Prescribe the behavior in "empty" case when there is nothing to refer to.
  • Não deve enviar por push autores de API para decisões de design que prejudicam o uso do tipo fora do fixed.Should not push API authors toward design decisions that hurt the use of the type outside of fixed.

Acho que a acima pode ser satisfeita reconhecendo um membro de retorno de referência de ref-renomeado especialmente: ref [readonly] T GetPinnableReference().I think the above could be satisfied by recognizing a specially named ref-returning member: ref [readonly] T GetPinnableReference().

Para ser usado pela instrução fixed, as seguintes condições devem ser atendidas:In order to be used by the fixed statement the following conditions must be met:

  1. Há apenas um desses membros fornecido para um tipo.There is only one such member provided for a type.
  2. Retorna por ref ou ref readonly.Returns by ref or ref readonly. (readonly é permitido para que os autores de tipos imutáveis/ReadOnly pudessem implementar o padrão sem adicionar uma API gravável que pudesse ser usada em código seguro)(readonly is permitted so that authors of immutable/readonly types could implement the pattern without adding writeable API that could be used in safe code)
  3. T é um tipo não gerenciado.T is an unmanaged type. (como T* se torna o tipo de ponteiro.(since T* becomes the pointer type. Naturalmente, a restrição expandirá se/quando a noção de "não gerenciado" for expandida)The restriction will naturally expand if/when the notion of "unmanaged" is expanded)
  4. Retorna nullptr gerenciado quando não há dados para fixar – provavelmente a maneira mais barata de transmitir a esvaziação.Returns managed nullptr when there is no data to pin – probably the cheapest way to convey emptiness. (Observe que "" a cadeia de caracteres retorna uma referência a ' \ 0 ', uma vez que as cadeias são terminadas em nulo)(note that “” string returns a ref to '\0' since strings are null-terminated)

Como alternativa para o #3, podemos permitir que o resultado em casos vazios seja indefinido ou específico da implementação.Alternatively for the #3 we can allow the result in empty cases be undefined or implementation-specific. No entanto, isso pode tornar a API mais perigosa e propenso a abusos e incômodos de compatibilidade indesejados.That, however, may make the API more dangerous and prone to abuse and unintended compatibility burdens.

TraduçãoTranslation

fixed(byte* ptr = thing)
{ 
    // <BODY>
}

torna-se o pseudocódigo a seguir (nem C#todos expressos no)becomes the following pseudocode (not all expressible in C#)

byte* ptr;
// specially decorated "pinned" IL local slot, not visible to user code.
pinned ref byte _pinned;

try
{
    // NOTE: null check is omitted for value types 
    // NOTE: `thing` is evaluated only once (temporary is introduced if necessary) 
    if (thing != null)
    {
        // obtain and "pin" the reference
        _pinned = ref thing.GetPinnableReference();

        // unsafe cast in IL
        ptr = (byte*)_pinned;
    }
    else
    {
        ptr = default(byte*);
    }

    // <BODY> 
}
finally   // finally can be omitted when not observable
{
    // "unpin" the object
    _pinned = nullptr;
}

DesvantagensDrawbacks

  • O GetPinnableReference destina-se a ser usado somente em fixed, mas nada impede seu uso em código seguro, portanto, o implementador deve ter isso em mente.GetPinnableReference is intended to be used only in fixed, but nothing prevents its use in safe code, so implementor must keep that in mind.

AlternativasAlternatives

Os usuários podem introduzir GetPinnableReference ou membro semelhante e usá-lo comoUsers can introduce GetPinnableReference or similar member and use it as

fixed(byte* ptr = thing.GetPinnableReference())
{ 
    // <BODY>
}

Não há solução para System.String se for desejada uma solução alternativa.There is no solution for System.String if alternative solution is desired.

Perguntas não resolvidasUnresolved questions

  • [] Comportamento no estado "Empty".[ ] Behavior in "empty" state. - nullptr ou undefined? - nullptr or undefined ?
  • [] Os métodos de extensão devem ser considerados?[ ] Should the extension methods be considered ?
  • [] Se um padrão for detectado em System.String, ele deverá vencer?[ ] If a pattern is detected on System.String, should it win over ?

Criar reuniõesDesign meetings

Nenhum ainda.None yet.