Подтвердить что ты не робот

С# Небезопасный/исправленный код

Может ли кто-нибудь дать пример хорошего времени для фактического использования "небезопасных" и "фиксированных" в коде С#? Я играл с ним раньше, но на самом деле не нашел для этого хорошей пользы.

Рассмотрим этот код...

fixed (byte* pSrc = src, pDst = dst) {
    //Code that copies the bytes in a loop
}

по сравнению с простым использованием...

Array.Copy(source, target, source.Length);

Второй - это код, найденный в .NET Framework, первый часть кода, скопированного с веб-сайта Microsoft, http://msdn.microsoft.com/en-us/library/28k1s2k6(VS.80).aspx.

Встроенный массив Array.Copy() значительно быстрее, чем использование небезопасного кода. Это может быть просто потому, что второе лучше написано лучше, а первое - просто пример, но в каких ситуациях вам действительно понадобится использовать Unsafe/Fixed код для чего-нибудь? Или этот бедный веб-разработчик возится с чем-то над его головой?

4b9b3361

Ответ 1

Это полезно для взаимодействия с неуправляемым кодом. Любые указатели, переданные неуправляемым функциям, должны быть исправлены (они закодированы), чтобы предотвратить сборщик мусора от перемещения основной памяти.

Если вы используете P/Invoke, тогда маршаллер по умолчанию будет связывать объекты для вас. Иногда необходимо выполнить настраиваемую сортировку, а иногда необходимо привязать объект дольше, чем длительность одного вызова P/Invoke.

Ответ 2

Я использовал небезопасные блоки для управления Bitmap-данными. Необработанный указатель-доступ значительно быстрее, чем SetPixel/GetPixel.

unsafe
{
    BitmapData bmData = bm.LockBits(...)
    byte *bits = (byte*)pixels.ToPointer();
    // Do stuff with bits
}

"фиксированный" и "небезопасный" обычно используется при взаимодействии или когда требуется дополнительная производительность. То есть. String.CopyTo() использует небезопасные и фиксированные в своей реализации.

Ответ 3

поведение стиля reinterpret_cast

Если вы немного манипулируете, это может быть невероятно полезно

Многие высокопроизводительные реализации hashcode используют UInt32 для хеш-значения (это упрощает смену). Поскольку .Net требует Int32 для метода, который вы хотите быстро преобразовать uint в int. Поскольку не имеет значения фактическое значение, только то, что все биты в значении сохранены, требуется реинтерпрет.

public static unsafe int UInt32ToInt32Bits(uint x)
{
    return *((int*)(void*)&x);
}

обратите внимание, что именование моделируется BitConverter.DoubleToInt64Bits

Продолжая в хешинговой вене, преобразование структуры на основе стека в байты * позволяет легко использовать хэш-функции байта:

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

небезопасно (начиная с версии 2.0), вы можете использовать stackalloc. Это может быть очень полезно в ситуациях высокой производительности, когда необходим небольшой массив переменной длины, такой как временное пространство.

Все эти применения были бы твердо "только в том случае, если вашему приложению действительно нужна производительность", и поэтому они неприемлемы для общего использования, но иногда вам это действительно нужно.

fixed необходимо, когда вы хотите взаимодействовать с некоторой полезной неуправляемой функцией (их много), которая принимает c-style массивы или строки. Таким образом, это не только по соображениям производительности, но и по правильности в сценариях взаимодействия.

Ответ 4

Небезопасно полезно (например) быстро получать данные о пикселях из изображения с помощью LockBits. Повышение производительности за счет использования управляемого API на несколько порядков.

Ответ 5

Нам пришлось использовать фиксированное значение, когда адрес передается в устаревшую C DLL. Поскольку DLL поддерживала внутренний указатель на вызовы функций, все ад бы разрывался, если GC уплотнял кучу и перемещал вещи вокруг.

Ответ 6

Я считаю, что небезопасный код используется, если вы хотите получить доступ к чему-то вне среды выполнения .NET, т.е. это не управляемый код (без сбора мусора и т.д.). Это включает в себя необработанные вызовы в Windows API и весь этот джаз.

Ответ 7

Это говорит о том, что разработчики платформы .NET хорошо справлялись с проблемным пространством - чтобы среда "управляемый код" могла делать все, что может сделать традиционный (например, С++) подход с его небезопасным кодом/указатели. Если это не возможно, небезопасные/фиксированные функции есть, если они вам понадобятся. Я уверен, что у кого-то есть пример, где нужен небезопасный код, но на практике он редко встречается - это скорее точка, не так ли?:)