Небезопасный / Исправленный код на C #
Вопрос
Может кто-нибудь привести пример подходящего времени для фактического использования "небезопасных" и "исправленных" в коде C #?Я играл с ним раньше, но так и не нашел ему хорошего применения.
Рассмотрим этот код...
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 (ПРОТИВ 80).aspx.
Встроенный массив.Copy() работает значительно быстрее, чем при использовании небезопасного кода.Это может быть просто потому, что второе просто лучше написано, а первое - всего лишь пример, но в каких ситуациях вам действительно нужно было бы использовать небезопасный / фиксированный код для чего-либо?Или этот бедный веб-разработчик возится с чем-то у себя над головой?
Решение
Это полезно для взаимодействия с неуправляемым кодом.Любые указатели, передаваемые на неуправляемые функции, должны быть исправлены (иначе.закреплено), чтобы предотвратить перемещение базовой памяти сборщиком мусора.
Если вы используете P / Invoke, то маршаллер по умолчанию закрепит объекты за вас.Иногда необходимо выполнить пользовательскую сортировку, а иногда необходимо закрепить объект на срок, превышающий продолжительность одного вызова P / Invoke.
Другие советы
Я использовал небезопасные блоки для манипулирования растровыми данными.Необработанный доступ к указателю осуществляется значительно быстрее, чем SetPixel / GetPixel.
unsafe
{
BitmapData bmData = bm.LockBits(...)
byte *bits = (byte*)pixels.ToPointer();
// Do stuff with bits
}
"исправлено" и "небезопасно" обычно используются при выполнении взаимодействия или когда требуется дополнительная производительность.Т.е.String.CopyTo() использует unsafe и исправлено в его реализации.
поведение в стиле reinterpret_cast
Если вы немного манипулируете, то это может быть невероятно полезно
многие высокопроизводительные реализации хэш-кода используют UInt32 для хэш-значения (это упрощает переключение).Поскольку .Net требует Int32 для метода, который вы хотите быстро преобразовать uint в int.Поскольку важно не то, каково фактическое значение, а только то, что все биты в значении сохранены, требуется приведение по-новому.
public static unsafe int UInt32ToInt32Bits(uint x)
{
return *((int*)(void*)&x);
}
обратите внимание, что именование составлено по образцу Конвертер битов.Удвоение 64 бит
Продолжая в духе хеширования, преобразование структуры на основе стека в байт * позволяет легко использовать функции хеширования на байт:
// 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);
}
unsafe также (начиная с версии 2.0) позволяет использовать stackalloc .Это может быть очень полезно в ситуациях с высокой производительностью, когда требуется некоторый небольшой массив переменной длины, например временное пространство.
Все эти варианты использования были бы строго регламентированы "только в том случае, если вашему приложению действительно нужна производительность" и, следовательно, неуместны при общем использовании, но иногда вам это действительно нужно.
исправлено необходимо, когда вы хотите взаимодействовать с какой-либо полезной неуправляемой функцией (их много), которая принимает массивы или строки в стиле c.Как таковой, это делается не только по соображениям производительности, но и корректности в сценариях взаимодействия.
Unsafe полезен (например) для быстрого извлечения пиксельных данных из изображения с помощью LockBits.Повышение производительности по сравнению с использованием управляемого API составляет несколько порядков.
Нам пришлось использовать исправленный, когда адрес передается в устаревшую библиотеку DLL C.Поскольку библиотека DLL поддерживала внутренний указатель при вызовах функций, весь ад вырвался бы на свободу, если бы GC уплотнил кучу и переместил материал.
Я считаю, что небезопасный код используется, если вы хотите получить доступ к чему-то за пределами .NET runtime, т.е.это не управляемый код (нет сборки мусора и так далее).Это включает в себя необработанные вызовы Windows API и весь этот джаз.
Это говорит мне о том, что разработчики .NET Framework проделали хорошую работу по охвату проблемного пространства - убедились, что среда "управляемого кода" может делать все традиционное (напримерC ++) подход может обойтись своим небезопасным кодом / указателями.В случае, если это невозможно, существуют небезопасные / исправленные функции, если они вам нужны.Я уверен, что у кого-то есть пример, когда требуется небезопасный код, но на практике это кажется редкостью - в чем, скорее, и суть, не так ли?:)