C # inseguro / Fixo Código
Pergunta
Alguém pode dar um exemplo de um bom momento para realmente usar "inseguro" e "fixo" no código C #? Eu joguei com ele antes, mas nunca realmente encontrei um bom uso para ele.
Considere este código ...
fixed (byte* pSrc = src, pDst = dst) {
//Code that copies the bytes in a loop
}
em comparação com simplesmente usando ...
Array.Copy(source, target, source.Length);
O segundo é o código encontrado no .NET Framework, a primeira parte do código copiado do site da Microsoft, http://msdn.microsoft.com/en-us/library/28k1s2k6 (VS.80) .aspx .
O construído em Array.Copy () é dramaticamente mais rápido do que usando o código inseguro. Este poder apenas porque o segundo é apenas melhor escrito e o primeiro é apenas um exemplo, mas que tipos de situações que você realmente precisa mesmo de usar / Código fixo inseguro para alguma coisa? Ou é este pobre desenvolvedor web mexer com algo acima de sua cabeça?
Solução
É útil para interoperabilidade com código não gerenciado. Os ponteiros passados ??para funções não gerenciadas precisam ser corrigidos (aka. Presa) para evitar que o coletor de lixo de realocar a memória subjacente.
Se você estiver usando P / Invoke, então o marshaller padrão irá fixar objetos para você. Às vezes é necessário realizar triagem costume, e às vezes é necessário fixar um objeto por mais tempo do que a duração de uma única chamada P / Invoke.
Outras dicas
Eu usei inseguras-blocos para manipular Bitmap-dados. ponteiro de acesso Raw é significativamente mais rápido do que SetPixel / GetPixel.
unsafe
{
BitmapData bmData = bm.LockBits(...)
byte *bits = (byte*)pixels.ToPointer();
// Do stuff with bits
}
"fixo" e "inseguro" é normalmente usado quando fazendo interoperabilidade, ou quando é necessária desempenho extra. Ie. String.CopyTo () usa inseguro e fixo na sua implementação.
comportamento estilo reinterpret_cast
Se você está pouco manipular, então isso pode ser extremamente útil
muitas implementações hashcode alto desempenho usar UInt32 para o valor de hash (isso torna as mudanças mais simples). Desde .Net requer Int32 para o método que você deseja converter rapidamente o uint para um int. Uma vez que não importa o que o valor real é, apenas que todos os bits no valor são preservadas um elenco reinterpretar é desejada.
public static unsafe int UInt32ToInt32Bits(uint x)
{
return *((int*)(void*)&x);
}
Note que a nomeação é modelado nas BitConverter.DoubleToInt64Bits
Continuando na veia hashing, convertendo um struct baseado em pilha em um byte * permite o fácil uso de per funções hash bytes:
// from the Jenkins one at a time hash function
private static unsafe void Hash(byte* data, int len, ref uint hash)
{
for (int i = 0; i < len; i++)
{
hash += data[i];
hash += (hash << 10);
hash ^= (hash >> 6);
}
}
public unsafe static void HashCombine(ref uint sofar, long data)
{
byte* dataBytes = (byte*)(void*)&data;
AddToHash(dataBytes, sizeof(long), ref sofar);
}
inseguro também (de 2,0 em diante) permite que você use stackalloc. Isto pode ser muito útil em situações de alto desempenho onde é necessária alguma variedade pequena de comprimento variável como espaço temporário.
Todos estes usos seria firmemente no 'apenas se o aplicativo realmente precisa do desempenho e, portanto, são inadequadas de uso geral, mas às vezes você realmente precisa fazer isso.
fixo é necessário para quando você deseja interoperabilidade com alguma função não gerenciada útil (há muitos) que leva matrizes ou seqüências de c-estilo. Como tal, não é apenas por motivos de desempenho, mas os de correção quando em cenários de interoperabilidade.
inseguro é útil para (por exemplo) dados de pixel sair de uma imagem rapidamente usando LockBits. A melhoria de desempenho ao longo de fazer isso usando a API gerenciada é várias ordens de magnitude.
Nós tivemos que usar um fixo quando um endereço é passada para um legado C DLL. Desde que a DLL mantém um ponteiro interno através de chamadas de função, todo o inferno iria quebrar solto se o GC compactado pilha e outras coisas movimentados.
Eu acredito código inseguro é usado se você deseja acessar algo fora do tempo de execução .NET, ie. ele não é o código gerenciado (sem coleta de lixo e assim por diante). Isso inclui chamadas matérias para a API do Windows e todo esse jazz.
Isto diz-me os projetistas do framework .NET fez um bom trabalho de cobrir o espaço do problema - de garantir o meio ambiente "código gerenciado" pode fazer tudo o que uma abordagem tradicional (por exemplo, C ++) pode fazer com o seu código inseguro / ponteiros. No caso, não pode, as características inseguras / fixo estão lá se você precisar deles. Tenho certeza de que alguém tem um exemplo onde é necessário código inseguro, mas parece raro na prática - que é um pouco o ponto, não é? :)