С# Небезопасный/исправленный код
Может ли кто-нибудь дать пример хорошего времени для фактического использования "небезопасных" и "фиксированных" в коде С#? Я играл с ним раньше, но на самом деле не нашел для этого хорошей пользы.
Рассмотрим этот код...
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 код для чего-нибудь? Или этот бедный веб-разработчик возится с чем-то над его головой?
Ответы
Ответ 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 хорошо справлялись с проблемным пространством - чтобы среда "управляемый код" могла делать все, что может сделать традиционный (например, С++) подход с его небезопасным кодом/указатели. Если это не возможно, небезопасные/фиксированные функции есть, если они вам понадобятся. Я уверен, что у кого-то есть пример, где нужен небезопасный код, но на практике он редко встречается - это скорее точка, не так ли?:)