{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "Богдан Стефанюк: дописи з тегом перевод",
    "_rss_description": "Всім привіт! Я — Богдан, фулстек розробник з Києва. Пишу в основному про програмування та штуки які вивчаю. Час від часу публікую підбірки фоток, зроблених на плівку, розказую про подорожі та цікаві речі, що оточують мене.",
    "_rss_language": "uk",
    "_itunes_email": "",
    "_itunes_categories_xml": "",
    "_itunes_image": "",
    "_itunes_explicit": "",
    "home_page_url": "https:\/\/stefaniuk.website\/tags\/perevod\/",
    "feed_url": "https:\/\/stefaniuk.website\/tags\/perevod\/json\/",
    "icon": "https:\/\/stefaniuk.website\/pictures\/userpic\/userpic@2x.jpg?1565716580",
    "authors": [
        {
            "name": "Bohdan Stefaniuk",
            "url": "https:\/\/stefaniuk.website\/",
            "avatar": "https:\/\/stefaniuk.website\/pictures\/userpic\/userpic@2x.jpg?1565716580"
        }
    ],
    "items": [
        {
            "id": "60",
            "url": "https:\/\/stefaniuk.website\/all\/best-practices-for-using-powershell-with-teamcity\/",
            "title": "Лучшие практики использования PowerShell c TeamCity",
            "content_html": "<p>Данная статья является переводом. <a href=\"https:\/\/cezarypiatek.github.io\/post\/best-practices-for-using-powershell-with-teamcity\/?utm_campaign=dotNET%20Weekly&utm_medium=email&utm_source=week-15_year-2019\">Оригинальная статья<\/a>.<\/p>\n<h2>Правильная обработка ошибок<\/h2>\n<p>Наиболее распространенная проблема заключается в том, что TeamCity игнорирует ошибки Powershell, по крайней мере, в конфигурации по умолчанию. Если шаг со сценарием PowerShell завершится неудачно, TeamCity по-прежнему считает билд успешным. Это может привести к серьезным ошибкам, которые могут быть незаметны длительное время. Это происходит потому что значение настройки <i>Format stderr output as<\/i> установлено в <i>warning<\/i>. Для того чтобы TeamCity видел ошибки, необходимо переключить настройку в <i>error<\/i>.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/stefaniuk.website\/pictures\/error_handling_for_ps.jpg\" width=\"917\" height=\"576\" alt=\"\" \/>\n<\/div>\n<p>Но это еще не все. Может возникнуть ситуация что шаг PowerShell упал но весь пайплайн признан успешным. Для этого нужно перейти в раздел <i>Failure Conditions<\/i> и установить флаг <i>error message is logged by build runner<\/i>.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/stefaniuk.website\/pictures\/teamcity_failure_condition.jpg\" width=\"848\" height=\"312\" alt=\"\" \/>\n<\/div>\n<p>Теперь все ошибки буду корректно обрабатываться и влиять на статус билда.<\/p>\n<p>Также надо понимать модель ошибок в PowerShell. Они могут поделятся на 2 группы:<\/p>\n<ol start=\"1\">\n<li>Завершающие (зачастую синтаксические ошибки).<\/li>\n<li>Не завершающие.<\/li>\n<\/ol>\n<p>Если возникло не завершающее исключение, то выполнение скрипта продолжится. Этот эффект может быть крайне нежелательным для сценариев, выполняющих взаимосвязанные операции, зависящие друг от друга. Конечно, мы можем изменить это поведение и превратить все «не завершающиеся» ошибки в «завершающиеся», установив переменную $ErrorActionPreference в начале наших скриптов:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">#Error Action Preference:\r\n#\r\n# SilentlyContinue – error messages are suppressed and execution continues.\r\n# Stop – forces execution to stop, behaving like a terminating error.\r\n# Continue - the default option. Errors will display and execution will continue.\r\n# Inquire – prompt the user for input to see if we should proceed.\r\n# Ignore – (new in v3) – the error is ignored and not logged to the error stream. Has very restricted usage scenarios.\r\n\r\n$ErrorActionPreference = &quot;Stop&quot;<\/code><\/pre><h2>Защита от случайных ошибок<\/h2>\n<p>Для начала необходимо превратить все наши функции в настоящие командлеты. Для этого нужно определять входящие параметры с помощью блока <i>param()<\/i> и пометить его атрибутом <i>[CmdletBinding()]<\/i>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">function Verb-Noun {\r\n    [CmdletBinding()]\r\n    param (\r\n     #parameters go here   \r\n    )    \r\n}<\/code><\/pre><p>Этот атрибут защищает вызов метода с не определенными параметрами. Каждый раз как кто-то использует не определенный\/удаленный параметр или делает ошибку в его названии, PowerShell выбросит ошибку. Если метод не помечен атрибутов, имена параметров не проверяются, что затрудняет обнаружение проблемы.<\/p>\n<p>Также можно обнаружить потенциальные ошибки, вызванные нарушением лучших практик и правил кодирования, включив строгий режим. Чтобы сделать это, добавьте следующий код в начале вашего скрипта:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">Set-StrictMode -Version Latest<\/code><\/pre><p>Детальнее можно почитать <a href=\"https:\/\/docs.microsoft.com\/en-us\/powershell\/module\/microsoft.powershell.core\/set-strictmode?view=powershell-6\">тут<\/a>.<\/p>\n<p>Вообще советую использовать VS Core и плагином PowerShell. Он превращает вашу в IDE в аналог PowerShell ISE. Также этот плагин поставляется с PSScriptAnalyzer, что позволяет обнаруживать разные ошибки.<\/p>\n<h2>Использование скриптов<\/h2>\n<p>Teamcity дает возможность запускать скрипты не только из файла, но и из встроенного редактора. Но лучшей практикой считается использование файлов. Это позволит держать скрипты в системе контроля версий, вместе с вашим проектом.<\/p>\n<h2>Всегда помните о чистом коде.<\/h2>\n<p>Ваши скрипты как и код вашего проекта должен лежать в системе контроля версий, покрыт тестами и пройти ревью. <a href=\"https:\/\/github.com\/PoshCode\/PowerShellPracticeAndStyle\">Здесь<\/a> вы можете найти лучшие практики и стили кодирования для PowerShell. Для тестирования кода можете использовать — <a href=\"https:\/\/github.com\/pester\/Pester\">Pester<\/a>.<\/p>\n<h2>Итог<\/h2>\n<p>Связка PowerShell и Teamcity позволяет создать действительно мощный CI\/CD. Но без понимания базовых принципов и механизмов вы не достигните максимального профита. Настройки по умолчанию часто могут приводить к непредвиденным ошибкам.<\/p>\n<h2>Ссылки<\/h2>\n<ol start=\"1\">\n<li><a href=\"https:\/\/github.com\/PoshCode\/PowerShellPracticeAndStyle\">Практики и стили кодирования для PowerShell скриптов.<\/a><\/li>\n<li>((<a href=\"https:\/\/github.com\/pester\/Pester\">https:\/\/github.com\/pester\/Pester<\/a> Pester — тест и мок фреймворк для PowerShell.)<\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/powershell\/module\/microsoft.powershell.core\/set-strictmode?view=powershell-6\">PowerShell strict mode<\/a>.<\/li>\n<\/ol>\n",
            "date_published": "2019-05-12T13:57:44-04:00",
            "date_modified": "2020-12-26T16:42:06-04:00",
            "tags": [
                "powershell",
                "перевод"
            ],
            "image": "https:\/\/stefaniuk.website\/pictures\/error_handling_for_ps.jpg",
            "_date_published_rfc2822": "Sun, 12 May 2019 13:57:44 -0400",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "60",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": [
                    "https:\/\/stefaniuk.website\/pictures\/error_handling_for_ps.jpg",
                    "https:\/\/stefaniuk.website\/pictures\/teamcity_failure_condition.jpg"
                ]
            }
        },
        {
            "id": "4",
            "url": "https:\/\/stefaniuk.website\/all\/debug-vs-release-builds-when-debbuging\/",
            "title": "C# Debug vs Release. Сборки и дебаг",
            "content_html": "<p>Оригинальная статья: <a href=\"http:\/\/benhall.io\/c-debug-vs-release-builds-and-debugging-in-visual-studio-from-novice-to-expert-in-one-blog-article\/?utm_campaign=dotNET%20Weekly&utm_medium=email&utm_source=week-21_year-2018\">тык<\/a>.<\/p>\n<p>Из коробки в C# нам доступны 2 способа сборки проекта release и debug.<\/p>\n<h2>О компиляции C# кода<\/h2>\n<p>Исходный код C # проходит через 2 этапа компиляции, чтобы стать инструкциями CPU, которые могут быть выполнены.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/stefaniuk.website\/pictures\/1.png\" width=\"606\" height=\"223\" alt=\"\" \/>\n<\/div>\n<p>Обычно первый этап происходит на вашем CI сервере, а второй шаг происходит позже, во время работы самого приложения. Когда же мы работаем локально в Visual Studio, то она все эти шаги выполняет перед запуском приложения из меню Debug.<\/p>\n<p><b>Шаг первый. Компиляция приложения<\/b><br \/>\nВаш код превращается в Common Intermediate Language (CIL), который уже может быть выполнен в любом окружении, которое поддерживает CIL. Обратите внимание, что собранная сборка не является читаемым текстом IL, а фактически метаданными и байтовым кодом в виде двоичных данных.<\/p>\n<p>На данном шаге будет выполнена некоторая оптимизация кода (будет описано дальше).<\/p>\n<p><b>Шаг второй. JIT компилятор<\/b><br \/>\nJIT компилятор конвертирует IL код в инструкции процессора, которые можно выполнить на вашей машине. Однако не вся компиляция происходит заранее — в нормальном режиме, код компилируется, только тогда когда его вызывают в первый раз, после чего он кэшируется.<\/p>\n<p>Компилятор JIT — это всего лишь один из целого ряда сервисов, которые составляют Common Language Runtime (CLR), позволяя ему выполнять код .NET.<\/p>\n<p>Основная часть оптимизации кода будет проведена на этом шаге.<\/p>\n<h2>Что такое оптимизация кода в одном предложении?<\/h2>\n<p>Это процесс улучшения таких факторов, как скорость выполнения, размер кода, энергопотребление, а в случае .NET — время, которое требуется для компилятора JIT — без изменения функциональности.<\/p>\n<h2>Почему мы заинтересованы в оптимизации в этой статье?<\/h2>\n<p>На обоих этапах компиляции ваш код будет оптимизирован компиляторами. Одно из ключевых различий между конфигурациями сборки Debug и Release заключается в том, отключены ли оптимизации или нет, поэтому нам нужно понять последствия данных оптимизации.<\/p>\n<h2>Оптимизация компилятора C#<\/h2>\n<p>C# компилятор на самом деле делает очень мало оптимизаций. На самом деле большенство оптимизаций производит JIT компилятор во время генерирования машинного кода. Тем не менее это все равно ухудшит работу по отладке.<\/p>\n<p><b>Инструкция nop в IL<\/b><br \/>\nКоманда nop имеет ряд применений при программировании на низком уровне, например, для включения небольших предсказуемых задержек или инструкции по перезаписи, которые вы хотите удалить. В IL коде данные конструкции помогают при использовании точек останова (breakpoints) для того чтобы они вели себя предсказуемо.<\/p>\n<p>Если мы посмотрим на IL код, который сгенерирован с отключенными оптимизациями:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/stefaniuk.website\/pictures\/2.png\" width=\"314\" height=\"31\" alt=\"\" \/>\n<\/div>\n<p>Эта инструкция мапиться с фигурной скобкой, для того чтобы мы могли поставить на нее точку остановки:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/stefaniuk.website\/pictures\/3.png\" width=\"386\" height=\"32\" alt=\"\" \/>\n<\/div>\n<p>Даная инструкция была бы удалена если у нас включены оптимизации, что повлияло бы на отладку приложения.<\/p>\n<p>Более подробное обсуждение оптимизаций компилятора C#  в статье Эрика Липперта: <a href=\"https:\/\/blogs.msdn.microsoft.com\/ericlippert\/2009\/06\/11\/what-does-the-optimize-switch-do\">Что делает переключатель оптимизации?<\/a>. Существует также хороший комментарий о IL до и после оптимизации <a href=\"https:\/\/stackoverflow.com\/questions\/21438751\/c-sharp-compiler-optimizations?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa\">здесь<\/a>.<\/p>\n<h2>Оптимизация JIT компилятора<\/h2>\n<p>Несмотря на то, что он быстро выполняет свою работу во время выполнения, компилятор JIT также выполняет множество оптимизаций. О его внутренних деталях мало информации. Даже во время работы вашего приложения он производит профилирование и, возможно, перекомпилирование кода для повышения производительности.<br \/>\nХорошие примеры оптимизации с помощью JIT компилятора можете посмотреть <a href=\"https:\/\/www.codeproject.com\/Articles\/25801\/JIT-Optimizations\">здесь<\/a>.<\/p>\n<p>Я рассмотрю один пример, чтобы проиллюстрировать влияние оптимизации на отладку.<br \/>\n<b>Встраивание методов<\/b><\/p>\n<p>Для реальной оптимизации, сделанной компилятором JIT, я буду показывать инструкции по сборке. Это всего лишь макет на C #, чтобы дать вам общую идею.<\/p>\n<p>Предположим, что у меня есть:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">private long Add(int a, int b)\r\n{\r\n    return a + b;\r\n}\r\npublic void MethodA()\r\n{\r\n    var r = Add(a, b);\r\n}<\/code><\/pre><p>Компилятор JIT, скорее всего, выполнит встроенное расширение. Он заменит вызов метода Add() телом данного метода:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">public void MethodA()\r\n{\r\n    var r = a + b;\r\n}<\/code><\/pre><h2>Конфигурации сборки по умолчанию<\/h2>\n<p>Итак, теперь, когда мы обновили понимание компиляции .NET и двух «слоев» оптимизации, давайте взглянем на 2 конфигурации сборки, доступные «из коробки»:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/stefaniuk.website\/pictures\/4.png\" width=\"682\" height=\"268\" alt=\"\" \/>\n<\/div>\n<p>Довольно просто — релиз полностью оптимизирован, отладка совсем отсутствует, что, как вы сейчас знаете, имеет фундаментальное значение для того, насколько легко отлаживать ваш код. Но это просто поверхностное представление о возможностях аргументов отладки и оптимизации.<\/p>\n<h2>Внутренности аргументов оптимизации и отладки<\/h2>\n<p>Я попытался продемонстрировать данные аргументы из кода Roslyn и mscorlib. Теперь мы имеем следующие классы:<\/p>\n<ol start=\"1\">\n<li><a href=\"https:\/\/github.com\/dotnet\/roslyn\/blob\/master\/src\/Compilers\/CSharp\/Portable\/CommandLine\/CSharpCommandLineParser.cs\">CSharpCommandLineParser<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/roslyn\/blob\/9b8aa38370fe6ad4afa10add7fa5a5bac22a9355\/src\/Compilers\/CSharp\/Portable\/CodeGen\/CodeGenerator.cs\">CodeGenerator<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/roslyn\/blob\/master\/src\/Compilers\/Core\/Portable\/CodeGen\/ILEmitStyle.cs\">ILEmitStyle<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Microsoft\/referencesource\/blob\/master\/mscorlib\/system\/diagnostics\/debuggerattributes.cs\">debuggerattributes<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/roslyn\/blob\/ef41d39c55a63d9464cc4eb5344be4d8df6408d8\/src\/Compilers\/CSharp\/Portable\/CodeGen\/Optimizer.cs\">Optimizer<\/a><\/li>\n<li><a href=\"http:\/\/source.roslyn.io\/#Microsoft.CodeAnalysis\/Compilation\/OptimizationLevel.cs,faae3325158ce920\">OptimizationLevel<\/a><\/li>\n<\/ol>\n<p>Синие элементы обозначаю аргументы командной строки, а зеленые их представление в коде.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/stefaniuk.website\/pictures\/5.png\" width=\"605\" height=\"377\" alt=\"\" \/>\n<\/div>\n<h2>Перечисление OptimizationLevel<\/h2>\n<p><b>OptimizationLevel.Debug<\/b> отключает все оптимизации для C# и JIT компилятора с помощью DebuggableAttribute.DebuggingModes, который с помощью ildasm, мы можем видеть:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/stefaniuk.website\/pictures\/6.png\" width=\"637\" height=\"31\" alt=\"\" \/>\n<\/div>\n<p><b>OptimizationLevel.Release<\/b> включает все оптимизации (DebuggableAttribute.DebuggingModes = ( 01 00 02 00 00 00 00 00 )) что в свою очередь соответсвует DebuggingModes.IgnoreSymbolStoreSequencePoints<\/p>\n<p>При этом уровне оптимизации точки останова могут быть оптимизированы. Что приведет к тому что мы не сможем их поставить и остановиться.<\/p>\n<h2>Типы IL<\/h2>\n<p>Типы IL кода описаны в классе <a href=\"https:\/\/github.com\/dotnet\/roslyn\/blob\/master\/src\/Compilers\/Core\/Portable\/CodeGen\/ILEmitStyle.cs\">ILEmitStyle<\/a>.<\/p>\n<p>На диаграмме выше показано, что тип генерируемого IL кода C# компилятором зависит от OptimizationLevel.<br \/>\nАргумент <i>debug<\/i> не меняет его, за исключение аргумента <i>debug+<\/i> когда OptimizationLevel установлен в Release.<\/p>\n<ul>\n<li>ILEmitStyle.Debug — нету оптимизация IL в дополнение к добавлению nop инструкций для сопоставления точекостановки с IL.<\/li>\n<li>LEmitStyle.Release — полная оптимизация.<\/li>\n<li>ILEmitStyle.DebugFriendlyRelease — выполняет только те оптимизации, которые не помешаю отладке приложения.<\/li>\n<\/ul>\n<p>Следующий кусок кода продемонстрирует все это наглядно.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">if(optimizations == OptimizationLevel.Debug)\r\n{\r\n    _ilEmitStyle = ILEmitStyle.Debug;\r\n}\r\nelse\r\n{\r\n    _ilEmitStyle = IsDebugPlus() ?\r\n    ILEmitStyle.DebugFriendlyRelease :\r\n    ILEmitStyle.Release;\r\n}<\/code><\/pre><p>Комментарий в исходном файле Optimizer.cs гласит, что они не опускают никаких определенных  пользователем локальных переменных (примеры на 28 строчке) и не переносят значения в стек между операторами.<\/p>\n<p>Я рад, что прочитал это, так как я был немного разочарован своими собственными экспериментами в ildasm с debug +, поскольку все, что я видел, это сохранение локальных переменных.<\/p>\n<p>Нет намеренной «деоптимизации», например, добавления команд nop.<\/p>\n<h2>Разница между debug, debug:full и debug:pdbonly.<\/h2>\n<p>На самом деле разницы никакой нету, что подтверждает официальная документация:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/stefaniuk.website\/pictures\/7.png\" width=\"473\" height=\"68\" alt=\"\" \/>\n<\/div>\n<p>Результат остается одним и тем же — pdb файл создается.<br \/>\nПодгланув в <a href=\"https:\/\/github.com\/dotnet\/roslyn\/blob\/master\/src\/Compilers\/CSharp\/Portable\/CommandLine\/CSharpCommandLineParser.cs\">CSharpCommandLineParser<\/a> можем убедиться в этом. И для того чтобы проверить это, мне удалось отладить код с помощью WinDbg для обох аргументов (pdbonly и full).<\/p>\n<p>Они не влияют на оптимизацию кода.<br \/>\nКак плюсом могу отметить что <a href=\"https:\/\/github.com\/dotnet\/roslyn\/blob\/master\/docs\/compilers\/CSharp\/CommandLine.md\">документация на Github<\/a> более актуальна, но она не открывает свет на специфическое поведение для <i>debug+<\/i><\/p>\n<p>А что же такое этот ваш pdb файл?<br \/>\nВсе очень просто, данный файл содержит всю необходимую информацию для отладки DLL и EXE. Что помогает сопоставить отладчику IL код с инструкциями в оригинальном C# коде.<\/p>\n<h2>Что на счет debug+?<\/h2>\n<p>debug+ это особенный аргумент, который не может быть заменен с помощью <i>full<\/i> и <i>pdbonly<\/i>. Как многие заметили, данный аргумент соответствует <i>debug:full<\/i> — это на самом деле не совсем правда. Если мы используем аргумент <i>optimize-<\/i>, поведение будет таким же, но для <i>optimize+<\/i> будет свое собственное уникальное поведение (DebugFriendlyRelease).<\/p>\n<h2>debug- или без аргументов?<\/h2>\n<p>Значения по умолчанию, которые установлены в <a href=\"https:\/\/github.com\/dotnet\/roslyn\/blob\/master\/src\/Compilers\/CSharp\/Portable\/CommandLine\/CSharpCommandLineParser.cs\">CSharpCommandLineParser.cs<\/a>.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">bool debugPlus = false;\r\nbool emitPdb = false;<\/code><\/pre><p>а значения для <i>debug=<\/i>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">case &quot;debug-&quot;:\r\n    if (value != null)\r\n        break;\r\n \r\n    bool emitPdb = false;\r\n    bool debugPlus = false;<\/code><\/pre><p>Таким образом, мы можем с уверенностью сказать, что debug- и отсутствие аргументов отладки, приводет к одному и тому же эффекту — pdb файл не будет создан.<\/p>\n<h2>Запрет оптимизации JIT при загрузке модуля (Suppress JIT optimizations)<\/h2>\n<p>Флажок в разделе «Options->Debugging->General»  это опция для отладчика в Visual Studio и не повлияет на сборки, которые вы создаете.<\/p>\n<p>Вы должны теперь оценить, что компилятор JIT делает большую часть значительных оптимизаций и является большим препятствием для сопоставления исходного исходного кода для отладки. Если этот параметр включен, тогда он запросит DisableOptimizations.<\/p>\n<p>Обычно этот параметр включаю для того чтобы отладить внешние библиотеки или пакеты NuGet.<\/p>\n<p>Если мы хотим подключиться отладчиком Visual Studion к продакшен сборке, которая собрана в релизной конфигурации, то при наличии у нас pdb файла, мы может еще одним способом указать JIT компилятору, о том чтобы он не оптимизировал код. Для этого нужно добавить .ini файл с таким же названием как выполняемая библиотека и указать в нем:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">[.NET Framework Debugging Control]\r\nAllowOptimize=0<\/code><\/pre><h2>Что такое Just My Code?<\/h2>\n<p>По умолчанию эта настройка уже включена (Options->Debugging→Enable Just My Code) и отладчик думает что оптимизированный код не является пользовательским. Поэтому отладчик никогда не зайдет в такой код.<\/p>\n<p>Вы можете отключить данный флаг и это, теоретически, позволит вам поставить точку остановки. Но теперь вы отлаживаете код, оптимизированный как компиляторами C# так и JIT, который едва соответствуют исходному коду. В результате у вас будут такие артефакты отладки, как непредсказуемые переходы в коде и скорее все вам не получиться получить значения в локальных переменных.<\/p>\n<p>Этот параметр стоит отключать в том случае, когда у вас есть pdb файл.<\/p>\n<h2>Взглянем ближе на DebuggableAttribute<\/h2>\n<p>Выше я упомянул использование ildasm для изучения манифеста сборок для изучения DebuggableAttribute. Я также написал небольшой PowerShell скрипт для получения более дружественного результата (<a href=\"https:\/\/github.com\/benbhall\/DotNetGetDebuggableAttribute\">ссылка на скачивание<\/a>).<\/p>\n<p>Сборка Debug:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/stefaniuk.website\/pictures\/8.png\" width=\"528\" height=\"70\" alt=\"\" \/>\n<\/div>\n<p>Сборка Release:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/stefaniuk.website\/pictures\/9.png\" width=\"527\" height=\"64\" alt=\"\" \/>\n<\/div>\n<p>Вы можете игнорировать IsJITTrackingEnabled, поскольку он был проигнорирован компилятором JIT с .NET 2.0.<br \/>\nКомпилятор JIT всегда будет генерировать информацию для отслеживания во время отладки, чтобы сопоставлять IL с машинным кодом и отслеживать, где хранятся локальные переменные и аргументы функции.<\/p>\n<p><b>IsJITOptimizerDisabled<\/b> — просто проверяет DebuggingFlags на наявность DebuggingModes.DisableOptimizations. Он отвечает за включение оптимизация с помощью JIT.<\/p>\n<p><b>DebuggingModes.IgnoreSymbolStoreSequencePoints<\/b> — говорит отладчику выработать точки последовательности из IL кода вместо загрузки .pdb файла. Точки последовательности используются для сопоставления местоположений в коде IL с местоположениями в исходном коде C#. Если он включен, то JIT не будет загружать .pdb файл. Я не уверен, почему этот флаг добавляется в оптимизированные сборки компилятором C#.<br \/>\nТакже об этом флаге можно почитать <a href=\"https:\/\/blogs.msdn.microsoft.com\/rmbyers\/2005\/09\/08\/debuggingmodes-ignoresymbolstoresequencepoints\/\">здесь<\/a><\/p>\n<h2>Ключевые понятия<\/h2>\n<ol start=\"1\">\n<li><i>debug-<\/i> или отсутствие аргумента приводит к тому что не создается .pdb файл.<\/li>\n<li><i>debug<\/i>, <i>debug:full<\/i> и <i>debug:pdbonly<\/i> приводят к созданию .pdb файла. <i>debug+<\/i> делает тоже самое в случае когда установлен флаг <i>optimize-<\/i>.<\/li>\n<li><i>debug+<\/i> и <i>optimize+<\/i> создают такой IL код, который легче отлаживать.<\/li>\n<li>Каждый слой оптимизации ухудшает отладку кода.<\/li>\n<li>С .NET 2.0 компилятор JIT всегда будет генерировать информацию для отслеживания независимо от атрибута IsJITTrackingEnabled.<\/li>\n<li>Будь то сборка через VS или csc.exe, атрибут DebuggableAttribute теперь всегда присутствует.<\/li>\n<li><i>optimised+<\/i> создает бинарники, которые отладчик воспринимает как сторонний код. Это поведение управляется с помощью опции Just My Code, но при ее отключении вы можете получить очень сомнительный опыт отладки.<\/li>\n<\/ol>\n<h2>Теперь у вас есть выбор:<\/h2>\n<ol start=\"1\">\n<li>Debug: debug|debug:full|debug:pdbonly optimize+<\/li>\n<li>Release: debug-|no debug argument optimize+<\/li>\n<li>DebugFriendlyRelease: debug+ optimize+<\/li>\n<\/ol>\n",
            "date_published": "2018-11-24T19:52:16-04:00",
            "date_modified": "2019-02-26T09:15:57-04:00",
            "tags": [
                "dotnet",
                "перевод"
            ],
            "image": "https:\/\/stefaniuk.website\/pictures\/1.png",
            "_date_published_rfc2822": "Sat, 24 Nov 2018 19:52:16 -0400",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "4",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": [
                    "https:\/\/stefaniuk.website\/pictures\/1.png",
                    "https:\/\/stefaniuk.website\/pictures\/2.png",
                    "https:\/\/stefaniuk.website\/pictures\/3.png",
                    "https:\/\/stefaniuk.website\/pictures\/4.png",
                    "https:\/\/stefaniuk.website\/pictures\/5.png",
                    "https:\/\/stefaniuk.website\/pictures\/6.png",
                    "https:\/\/stefaniuk.website\/pictures\/7.png",
                    "https:\/\/stefaniuk.website\/pictures\/8.png",
                    "https:\/\/stefaniuk.website\/pictures\/9.png"
                ]
            }
        }
    ],
    "_e2_version": 4116,
    "_e2_ua_string": "Aegea 11.2 (v4116)"
}