Может ли кто-нибудь привести пример того, когда действительно можно использовать «небезопасно» и «исправлено» в коде 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(VS.80).aspx.
Встроенный Array.Copy () значительно быстрее, чем использование небезопасного кода. Это может быть просто потому, что второй просто лучше написан, а первый - просто пример, но в каких ситуациях вам действительно нужно использовать небезопасный / фиксированный код для чего-либо? Или этот бедный веб-разработчик возится с чем-то над головой?





Я считаю, что небезопасный код используется, если вы хотите получить доступ к чему-либо вне среды выполнения .NET, т.е. это не управляемый код (без сборки мусора и т. д.). Сюда входят необработанные вызовы Windows API и все такое.
рискованные мысли, сборщик мусора не активен для небезопасных методов / переменных / объектов, все в порядке, если вы работаете с существующими переменными и закрепляете такие структуры данных, однако это становится проблематичным, если вы расширяете область данных в небезопасных условиях, если это действительно так дела не так он жрет память, без контроля GBC. Тем не менее, можно иметь данные и использовать небезопасные методы для их обработки, если в процессе нет утечки, нет никакого риска, и после обработки GBC может взять на себя управление.
Нам пришлось использовать фиксированный, когда адрес передается в устаревшую C DLL. Поскольку DLL поддерживает внутренний указатель на вызовы функций, весь ад вырвется наружу, если сборщик мусора сжимает кучу и перемещает вещи.
Это говорит мне о том, что разработчики .NET framework хорошо поработали над проблемным пространством, убедившись, что среда «управляемого кода» может делать все, что традиционный (например, C++) подход может делать с ее небезопасным кодом / указателями. На случай, если это невозможно, есть небезопасные / фиксированные функции, если они вам понадобятся. Я уверен, что у кого-то есть пример, когда нужен небезопасный код, но на практике это кажется редкостью - в чем, скорее, суть, не так ли? :)
используется для обработки графики, используется быстрее, чем marshal.copy, используется для обработки данных в реальном времени и аудио. но вы, вероятно, не увидите его на среднем сайте MVC, часто встречающемся в сочетании с c / C++ / ассемблер.
Небезопасно полезно (например) для быстрого получения пиксельных данных из изображения с помощью LockBits. Повышение производительности по сравнению с использованием управляемого API составляет несколько порядков.
Это полезно для взаимодействия с неуправляемым кодом. Любые указатели, передаваемые неуправляемым функциям, должны быть исправлены (иначе говоря, закреплены), чтобы сборщик мусора не переместил базовую память.
Если вы используете P / Invoke, то маршаллер по умолчанию будет закреплять объекты за вас. Иногда необходимо выполнить настраиваемый маршаллинг, а иногда необходимо закрепить объект на время, превышающее продолжительность одного вызова P / Invoke.
Я использовал небезопасные блоки для управления растровыми данными. Доступ к необработанному указателю значительно быстрее, чем SetPixel / GetPixel.
unsafe
{
BitmapData bmData = bm.LockBits(...)
byte *bits = (byte*)pixels.ToPointer();
// Do stuff with bits
}
«fixed» и «unsafe» обычно используются при взаимодействии или когда требуется дополнительная производительность. Т.е. String.CopyTo () использует небезопасные и исправленные в своей реализации.
Я бы изменил «значительно» на «много порядков». Невероятно, насколько медленны SetPixel и GetPixel. Доступ к пикселям был быстрее на Apple IIe в 1980 году.
стиль поведения reinterpret_cast
Если вы немного манипулируете, это может быть невероятно полезно
многие высокопроизводительные реализации хэш-кода используют 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);
}
unsafe также (начиная с версии 2.0) позволяет использовать stackalloc. Это может быть очень полезно в ситуациях с высокой производительностью, когда требуется небольшой массив переменной длины, например временное пространство.
Все эти варианты использования строго относятся к категории «только в том случае, если вашему приложению действительно нужна производительность» и, следовательно, не подходят для общего использования, но иногда вам это действительно нужно.
fixed необходим, когда вы хотите взаимодействовать с какой-либо полезной неуправляемой функцией (их много), которая принимает массивы или строки в стиле c. Таким образом, это делается не только из соображений производительности, но и из соображений корректности в сценариях взаимодействия.
почему вы упомянули reinterpret_cast? какая параллель с небезопасным / исправленным?
@ Guillame07 Потому что для прямого выполнения (в отличие от использования объединений в структурах) требуется небезопасный контекст
«Небезопасный» не означает «Неуправляемый». Небезопасные методы в C# - это управляемые методы, которым разрешено манипулировать указателями. Однако код по-прежнему находится в ведении. Если вы хотите использовать неуправляемый (собственный) код в своем приложении, вы можете использовать C++ / CLI и его директивы #pragma.