<?xml version="1.0" encoding="UTF-8"?>

<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" >

  <channel>
    <title><![CDATA[Комментарии / Профиль csdev]]></title>
    <link>https://habr.com/ru/users/csdev/comments/</link>
    <description><![CDATA[Хабр: комментарии пользователя csdev]]></description>
    <language>ru</language>
    <managingEditor>editor@habr.com</managingEditor>
    <generator>habr.com</generator>
    <pubDate>Fri, 24 Apr 2026 02:02:16 GMT</pubDate>
    
    
      <image>
        <link>https://habr.com/ru/</link>
        <url>https://habrastorage.org/webt/ym/el/wk/ymelwk3zy1gawz4nkejl_-ammtc.png</url>
        <title>Хабр</title>
      </image>
    

    
      

      
        
  
    <item>
      <title>29.09.2025 16:23:44 </title>
      <guid isPermaLink="true">https://habr.com/ru/articles/943254/#comment_28897380</guid>
      <link>https://habr.com/ru/articles/943254/#comment_28897380</link>
      <description><![CDATA[<p>Интересные соображения. Да я и спорить не стану, что статья ангажирована. Программист, мечтавший попробовать с ПП, пытается убедить в его целесообразности себя и неких условных менеджеров.</p>]]></description>
      <pubDate>Mon, 29 Sep 2025 16:23:44 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>29.09.2025 16:17:00 </title>
      <guid isPermaLink="true">https://habr.com/ru/articles/943254/#comment_28897354</guid>
      <link>https://habr.com/ru/articles/943254/#comment_28897354</link>
      <description><![CDATA[<p>Интересно, гоняют ли их по теории как разработчиков при найме. Хотя нас вот гоняют, а потом видишь <img class="formula inline" source="O(n^4)" alt="O(n^4)" src="https://habrastorage.org/getpro/habr/upload_files/fad/1d7/61d/fad1d761d85257bbd817c6a3fdbb4dff.svg" width="48" height="24">, где можно <img class="formula inline" source="O(n)" alt="O(n)" src="https://habrastorage.org/getpro/habr/upload_files/6cf/fa9/b92/6cffa9b9215f546eca7dc4c3887c2654.svg" width="39" height="21">, и копи-пасту спагетти-кода у людей с опытом 10+ лет.</p>]]></description>
      <pubDate>Mon, 29 Sep 2025 16:17:00 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>23.09.2025 18:22:04 </title>
      <guid isPermaLink="true">https://habr.com/ru/articles/943254/#comment_28873538</guid>
      <link>https://habr.com/ru/articles/943254/#comment_28873538</link>
      <description><![CDATA[<blockquote><p>Парно кодить это не только сложение компетенций</p></blockquote><p>С этого публикация и начинается. Что все сложно. Но бизнес по факту интересуют обычно только человеко-часы. И их же проще всего смоделировать.</p><blockquote><p>Ещё не обязательно иметь одинаковый грейд</p></blockquote><p>Возможно, я окуклился в энтерпрайзе, но уже лет как семь или больше джунов видел только на собеседованиях, безуспешно пытающимися выдать себя за миддлов. Один работодатель гордился корпаративными стажировками, но тех стажеров или их кода ни в одной продуктовой команде в глаза не видели. Работают люди уровня миддл и выше. Процентов 90-95 примерно одного уровня. Другие просто не проходят все этапы найма. Так что предпосылка одинаковых разработчиков продиктована не только стремлением к упрощению, но и личным опытом.</p><blockquote><p>Думаю, что есть проблема в самой модели</p></blockquote><p>Остальные немногочисленные предпосылки (ограниченность набора навыков, невозможность владения в совершенстве всеми ими и трудности про недостаточном владении) исходят из здравого смысла. Модель проста как пять копеек, просто воплощение программистского принципа KISS. Проблем бы ей как раз добавили дополнительные абстракции и предположения (бритва Окама).</p><p>Вывод делается тоже очень осторожный. Менеждеры как от огня, зажмурившись, шарахаются от ПП, а если присмотреться, то потенциально оно может быть целесообразно с точки зрения временных затрат при некоторых условиях. Каких - вопрос для отдельного изучения.</p><blockquote><p>в реальном мире часто декомпозируется и разделяется по исполнителям, которые обладают нужными знаниями</p></blockquote><p>В жизни все исполнители всегда обладают всеми знаниями хотя бы на уровне "где-то что-то слышал, сейчас поисковик/ИИ спрошу". И далеко не каждый проскочивший найм и испытательный срок признается, что местами не дотягивает. Как объективно определять нужного исполнителя? Что делать с командой, если на все задачи нужным окажется один и тот же человек?<br>Кстати, про декомпозицию в статье тоже можно найти.</p>]]></description>
      <pubDate>Tue, 23 Sep 2025 18:22:04 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>23.09.2025 18:21:31 </title>
      <guid isPermaLink="true">https://habr.com/ru/articles/943254/#comment_28873536</guid>
      <link>https://habr.com/ru/articles/943254/#comment_28873536</link>
      <description><![CDATA[<p>del. &lt;не туда&gt;</p>]]></description>
      <pubDate>Tue, 23 Sep 2025 18:21:31 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>23.12.2022 20:27:18 </title>
      <guid isPermaLink="true">https://habr.com/ru/companies/pvs-studio/articles/691476/#comment_25041828</guid>
      <link>https://habr.com/ru/companies/pvs-studio/articles/691476/#comment_25041828</link>
      <description><![CDATA[<p>Про выделение памяти полезно ещё в <strong>Diagnostic Tools</strong> глянуть на выходе из метода.</p><pre><code class="cs">static void Main()
{
    var count = 1000000;
    var collection = new ArrayList(count);
    for (var i = 0; i &lt; count; i++)
        collection.Add(i);
}</code></pre><p>Выше приведенный код даст помимо <code>ArrayList</code> миллион упакованных <code>Int32</code>.</p><figure class="full-width "><img src="https://habrastorage.org/getpro/habr/upload_files/e46/f0f/617/e46f0f6176665262fb43b3e66c9db7f7.png" width="702" height="264"><figcaption></figcaption></figure><p><code>ArrayList</code> здесь ссылается на <code>Object[]</code>, который ссылается на <code>Int32</code>.</p><figure class="full-width "><img src="https://habrastorage.org/getpro/habr/upload_files/def/3c3/fd7/def3c3fd777788d6abc23c717503b5a0.png" width="702" height="325"><figcaption></figcaption></figure><p>Использование <code>List&lt;int&gt;</code> дает другую картину.</p><pre><code class="cs">static void Main()
{
    var count = 1000000;
    var collection = new List&lt;int&gt;(count);
    for (var i = 0; i &lt; count; i++)
        collection.Add(i);
}</code></pre><figure class="full-width "><img src="https://habrastorage.org/getpro/habr/upload_files/b3f/70e/bab/b3f70ebab251a19f573459aa83d2e6c8.png" width="705" height="306"><figcaption></figcaption></figure><p>Никаких упакованных <code>Int32</code>. <code>List&lt;Int32&gt;</code> ссылается на <code>Int32[]</code>. Использование памяти значительно сокращено.</p><p></p>]]></description>
      <pubDate>Fri, 23 Dec 2022 20:27:18 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>25.08.2022 20:20:36 </title>
      <guid isPermaLink="true">https://habr.com/ru/companies/sportmaster_lab/articles/681010/#comment_24664320</guid>
      <link>https://habr.com/ru/companies/sportmaster_lab/articles/681010/#comment_24664320</link>
      <description><![CDATA[<p>Хрупкость тестов - это да. Но если Вы имеете в виду, что не стоит выставлять что-то наружу <strong>для всех</strong> только <strong>ради тестов</strong>, то это мудрая мысль. Публичный контракт - серьезное обязательство, а отказ от него сильно расстраивает пользователей, даже если делается по всем правилам этикета с предупреждениями <strong><em>obsolete</em></strong> в переходных версиях. Товарищ в <a href="https://habr.com/ru/company/sportmaster_lab/blog/681010/#comment_24623862" rel="noopener noreferrer nofollow">коментарии ниже</a> совершенно прав. Но существуют приемы открытия чего-то только для тестов. Вот есть класс:</p><pre><code class="cs">public class Subject
{
    private int value;
  
    public Subject(int value) =&gt; this.value = value;
}</code></pre><p>А нужен тривиальный тест, проверяющий присвоение значения полю в конструкторе. Тогда поле делаем видимым для наследника, а в тестопригодном наследнике выставляем наружу:</p><pre><code class="cs">public class Subject
{
    private int value;
  
    // exposing a private field to subclasses
    // is less harm than making it public
    protected int Value =&gt; value;
  
    public Subject(int value) =&gt; this.value = value;
}

public class TestableSubject : Subject
{
    // transitively grant client code (i.e.test)
    // access to the private field
    public new int Value =&gt; base.Value;
    
    public TestableSubject(int value) : base(value) { }
}</code></pre><p>И тестируем спокойно:</p><pre><code class="cs">[Test]
public void NormalTest()
{
    // Arrange
    int value = 42;

    // Act
    var sut = new TestableSubject(value);

    // Assert
    Assert.AreEqual(value, sut.Value);
}</code></pre><p>Правда, такой фокус потом любой пользователь библиотеки повторить сможет.</p><p>У .NET есть <a href="https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.internalsvisibletoattribute" rel="noopener noreferrer nofollow">InternalsVisibleToAttribute</a> и вообще рефлексия:</p><pre><code class="cs">public class Subject
{
    private int value;

    public Subject(int value) =&gt; this.value = value;
}

public class TestableSubject : Subject
{
    public int Value =&gt; (int)typeof(Subject).GetField("value",
        BindingFlags.NonPublic | BindingFlags.Instance)
        .GetValue(this);

    public TestableSubject(int value) : base(value) { }
}</code></pre><p>Еще для .NET есть штуки вроде <a href="https://github.com/Fody/Publicize" rel="noopener noreferrer nofollow">этой</a>, которые могут патчить код после компиляции. Клиенты получают оригинальную библиотеку, а тесты патченную с открытым доступом к чему угодно. Думаю, для других платформ аналоги тоже есть.</p><p></p>]]></description>
      <pubDate>Thu, 25 Aug 2022 20:20:36 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>25.08.2022 13:05:03 </title>
      <guid isPermaLink="true">https://habr.com/ru/articles/684056/#comment_24663308</guid>
      <link>https://habr.com/ru/articles/684056/#comment_24663308</link>
      <description><![CDATA[<p>Тесты, о которых Вы пишете - то, к чему надо стремиться. В рафинированном виде такие встречаются только в обучающих материалах по TDD. В жизни обычно приходишь на новый проект, смотришь на юнит тесты и ужасаешься. В некоторых компаниях их до сих пор вообще не применяют. А даже там, где юнит тестирование организованно более или менее прилично, могут быть иерархии наследования тестовых классов с переопределениями вспомогательных методов типа <em>SetUp()</em>, <em>TearDown()</em> или <em>CreateSut()</em>, чтобы не было дублирующегося кода. Если впадать в крайности пуризма, то такие методы даже без наследования тестовых классов надо объявлять ересью.</p><blockquote><p>может ли посторонний человек посмотреть на код теста...</p></blockquote><p>Это решается конвенционально. Также как, например, организации тестов по принципу AAA или создание sut только через CreateSut(). Просто вся команда знает (и в проекте даже соответствующая инструкция лежит), что если тест помечен <code>DeclarativeCaseAttribute&lt;TValidator, TScript, TCheck&gt;</code>, то для</p><pre><code class="cs">[TestFixture]
public class DemoTests : IDeclarativeTest
{
    public void Test&lt;TValidator, TScript, TCheck&gt;(bool expected)
        where TValidator : IValidator, new()
        where TScript : IScript, new()
        where TCheck : ICheck, new() =&gt;
        DefaultDeclarativeTest.Test&lt;TValidator, TScript, TCheck&gt;(expected);

    [DeclarativeCase&lt;OrdinaryValidator, AdvancedAttack, AttackDetected&gt;(false)]
    [DeclarativeCase&lt;AdvancedValidator, AdvancedAttack, AttackDetected&gt;(true)]
    public void TestAdvancedAttack() { }
}</code></pre><p>это означает, что фактически тест содержится в <code>void Test&lt;TValidator, TScript, TCheck&gt;(bool)</code> тестового класса, а для</p><pre><code class="cs">[TestFixture, Declarative]
public class DemoTests
{
    [DeclarativeCase&lt;OrdinaryValidator, AdvancedAttack, AttackDetected&gt;(false)]
    [DeclarativeCase&lt;AdvancedValidator, AdvancedAttack, AttackDetected&gt;(true)] 
    public void TestAdvancedAttack() { }
}</code></pre><p>подразумевается, что непосредственно код теста лежит в <code>void Test()</code> аттрибута (пара кликов/хот-кеев - и перед Вами фактическая реализация теста). Если так делать постоянно, то оно начнет восприниматься, как само собой разумеющееся. Многие ли задумываются о том, что происходит под капотом, когда для добавления теста просто пишут <code>[Test]</code>, а потом в Test Explorer видят результат его выполнения?</p><p>Вообще статья является продолжением другой публикации с пометкой <strong><em>"ненормальное программирование"</em></strong>. Я необоснованно предположил, что в сознании читающего этот аттрибут неявно наследуется. Сейчас исправлю. В обеих описывается не как нужно делать, а как можно. Вот пришла человеку в голову занимательная идея, он ее воплотить попытался, глубже в инструменты погрузился, столкнулся с ограничениями, но нашел workaround'ы, а свой опыт здесь описал. Наверное, с названием <strong><em>"Как хакнуть NUnit, чтобы заставить делать странное"</em></strong> воспринималось бы иначе.</p><p></p>]]></description>
      <pubDate>Thu, 25 Aug 2022 13:05:03 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>07.08.2022 12:16:52 </title>
      <guid isPermaLink="true">https://habr.com/ru/articles/508526/#comment_24605350</guid>
      <link>https://habr.com/ru/articles/508526/#comment_24605350</link>
      <description><![CDATA[<p>Или даже так:</p><pre><code class="cs">using System;

class Program
{
    static void Main()
    {
        Console.WriteLine(
            from @default in (object)default
            join _ in (object)default
            on default equals default
            where default
            group default
            by default
            into @default
            orderby default
            select default);
    }
}

static class Extensions
{
    public static object Join(
        this object outer,
        object inner,
        Func&lt;object, object&gt; outerKeySelector,
        Func&lt;object, object&gt; innerKeySelector,
        Func&lt;object, object, object&gt; resultSelector)
        =&gt; default;

    public static object Where(
        this object source,
        Func&lt;object, bool&gt; predicate)
        =&gt; default;

    public static object GroupBy(
        this object source,
        Func&lt;object, object&gt; keySelector,
        Func&lt;object, object&gt; elementSelector)
        =&gt; default;

    public static object OrderBy(
        this object source,
        Func&lt;object, object&gt; keySelector)
        =&gt; default;

    public static string Select(
        this object source,
        Func&lt;object, object&gt; selector)
        =&gt; "Hello, World!";
}</code></pre><p></p>]]></description>
      <pubDate>Sun, 07 Aug 2022 12:16:52 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>22.04.2022 21:44:11 </title>
      <guid isPermaLink="true">https://habr.com/ru/articles/662109/#comment_24291577</guid>
      <link>https://habr.com/ru/articles/662109/#comment_24291577</link>
      <description><![CDATA[<p>Вот автор вопроса на <code>System.dll</code> не ссылается, но если ему понадобятся <code>LinkedList&lt;T&gt;</code>, <code>ObservableCollection&lt;T&gt;</code> или <code>Timer</code> оттуда, то он её добавит. И тогда можно будет использовать <code>Process</code> из этой библиотеки:</p><pre><code class="cs">using (var process = Process.Start(
       new ProcessStartInfo(
           "cmd.exe",
           "/c echo WASTED&gt; &lt;file&gt;")
       {
           CreateNoWindow = true,
           UseShellExecute = false,
       }))
    process.WaitForExit();</code></pre><p></p>]]></description>
      <pubDate>Fri, 22 Apr 2022 21:44:11 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>22.04.2022 17:01:37 </title>
      <guid isPermaLink="true">https://habr.com/ru/articles/662109/#comment_24291025</guid>
      <link>https://habr.com/ru/articles/662109/#comment_24291025</link>
      <description><![CDATA[<p>Кроме Activator'а, там еще почти отсутствует защита от рефлексии. И вместо:</p><pre><code class="cs">var type = Type.GetType("System.IO.StreamWriter");
using (var sw = (IDisposable)Activator.CreateInstance(type, new object[] { "&lt;file&gt;" }))
    type.GetMethod("Write", new[] { typeof(string) }).Invoke(sw, new object[] { "WASTED" });</code></pre><p>можно, например:</p><pre><code class="cs">Type.GetType("System.IO.File")
    .GetMethod("WriteAllText", new[] { typeof(string), typeof(string) })
    .Invoke(null, new object[] { "&lt;file&gt;", "WASTED" });</code></pre><p>И вполне возможно, что на этом список уязвимостей не исчерпывается.</p>]]></description>
      <pubDate>Fri, 22 Apr 2022 17:01:37 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>22.04.2022 16:40:19 </title>
      <guid isPermaLink="true">https://habr.com/ru/articles/662109/#comment_24290969</guid>
      <link>https://habr.com/ru/articles/662109/#comment_24290969</link>
      <description><![CDATA[<p>Такого кодоанализатора, на сколько я знаю, нет. Из коробки есть песочница <a href="https://docs.microsoft.com/en-us/dotnet/api/system.appdomain?view=net-6.0#remarks" rel="noopener noreferrer nofollow">AppDomain</a>. Но в последних версиях фреймворка от нее осталось одно название. На поддержку <a href="https://docs.microsoft.com/en-us/dotnet/api/system.appdomain.permissionset?view=net-6.0#definition" rel="noopener noreferrer nofollow">AppDomain.PermissionSet</a>, таких, напрмер, как <a href="https://docs.microsoft.com/en-us/dotnet/api/system.security.permissions.fileiopermission?view=dotnet-plat-ext-6.0&amp;viewFallbackFrom=net-6.0#definition" rel="noopener noreferrer nofollow">FileIOPermission</a>, подзабили. Еще есть <a href="https://habr.com/ru/company/arcadia/blog/553596/" rel="noopener noreferrer nofollow">Managed Add-In Framework</a> для работы с плагинами. В новых версия фактически тоже <a href="https://habr.com/ru/company/arcadia/blog/553596/#comment_22962150" rel="noopener noreferrer nofollow">не поддерживается</a>.</p>]]></description>
      <pubDate>Fri, 22 Apr 2022 16:40:19 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>22.04.2022 16:32:53 </title>
      <guid isPermaLink="true">https://habr.com/ru/articles/662109/#comment_24290943</guid>
      <link>https://habr.com/ru/articles/662109/#comment_24290943</link>
      <description><![CDATA[<p>С одной стороны, да. А с другой, у автора вопроса может быть свой редактор кода с подсветкой синтаксиса, IntelliSense и прочим, и он хочет как-то визуально обращать внимание пользователя на недопустимые вызовы. Мы не знаем точно.</p>]]></description>
      <pubDate>Fri, 22 Apr 2022 16:32:53 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>23.12.2021 19:53:42 </title>
      <guid isPermaLink="true">https://habr.com/ru/companies/arcadia/articles/594681/#comment_23862111</guid>
      <link>https://habr.com/ru/companies/arcadia/articles/594681/#comment_23862111</link>
      <description><![CDATA[<p>Да, действительно, это скорее про особенности yield и того, что генерируется под копотом.<br> И код действительно нелинеен. Но, к счастью, и не параллелен, и поэтому наглядно пробегается в дебагере. Выглядит занятно. Особенное если это какое-нибудь нагромождение IEnumerable(IEnumerable(IEnumerable)) типа цепочек LINQ.</p><p>И про</p><blockquote><p>Да, вот как раз в этом и дело. По-моему, просто пока не будет первого MoveNext() выполнение метода с yield вообще даже не начнется.</p></blockquote><p>верно подмечено.</p><p>Поэтому, кстати, рекомендуют отделять проверки аргументов от yield. Иначе можно получить исключение в несовсем ожидаемом месте.</p><details class="spoiler"><summary>Пример:</summary><div class="spoiler__content"><p>Пусть есть такой код:</p><pre><code class="cs">static object CreateObject(object arg)
{
    if (arg == null)
        throw new ArgumentNullException(nameof(arg));

    return null;
}

static IEnumerable&lt;object&gt; CreateEnumerable(object arg)
{
    if (arg == null)
        throw new ArgumentNullException(nameof(arg));

    yield return null;
}

static void Test(object obj)
{
    if (obj is IEnumerable enumerable)
    {
        var enumerator = enumerable.GetEnumerator();
        Console.WriteLine(enumerator.ToString());
        Console.WriteLine(enumerator.GetType());
        Console.WriteLine(enumerator.GetHashCode());
        Console.WriteLine(enumerator.Equals(null));
        Console.WriteLine(enumerator.Current ?? "NULL");
        enumerator.MoveNext();
    }
}</code></pre><p>Тогда для <code>Test(CreateObject(null))</code> вывод будет:</p><pre><code>Unhandled exception. System.ArgumentNullException: Value cannot be null. (Parameter 'arg')
   at TryFinally.Program.CreateObject(Object arg) in C:\Users\Admin\source\repos\TryFinally\TryFinally\Program.cs:line 19
   at TryFinally.Program.Main(String[] args) in C:\Users\Admin\source\repos\TryFinally\TryFinally\Program.cs:line 11</code></pre><p>Вызов метода <code>Test</code> не произошел.</p><p>А для <code>Test(CreateEnumerable(null))</code>:</p><pre><code>TryFinally.Program+&lt;CreateEnumerable&gt;d__2
TryFinally.Program+&lt;CreateEnumerable&gt;d__2
58225482
False
NULL
Unhandled exception. System.ArgumentNullException: Value cannot be null. (Parameter 'arg')
   at TryFinally.Program.CreateEnumerable(Object arg)+MoveNext() in C:\Users\Admin\source\repos\TryFinally\TryFinally\Program.cs:line 27
   at TryFinally.Program.Test(Object obj) in C:\Users\Admin\source\repos\TryFinally\TryFinally\Program.cs:line 40
   at TryFinally.Program.Main(String[] args) in C:\Users\Admin\source\repos\TryFinally\TryFinally\Program.cs:line 11</code></pre><p>Метод <code>Test</code> не только был вызван, но и спокойно обращался к членам <code>enumerator</code> до вызова <code>enumerator.MoveNext()</code>.</p></div></details>]]></description>
      <pubDate>Thu, 23 Dec 2021 19:53:42 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>22.12.2021 14:33:31 </title>
      <guid isPermaLink="true">https://habr.com/ru/companies/arcadia/articles/594681/#comment_23856331</guid>
      <link>https://habr.com/ru/companies/arcadia/articles/594681/#comment_23856331</link>
      <description><![CDATA[<p>Кстати, <code>try-finally</code> с <code>foreach</code> имеет свои особенности.</p><p>Допустим, есть метод:</p><pre><code class="cs">IEnumerable&lt;int&gt; CountDown(int count, int? stopAt = null, int? failAt = null)
{
    try
    {
        while (count &gt; -1)
        {
            yield return count;

            if (count == stopAt)
                yield break;

            if (count == failAt)
                throw new Exception($"Inner failure at {nameof(count)} = {count}");

            count--;
        }
    }
    finally
    {
        Console.WriteLine("Finally!!!");
    }
}</code></pre><p>Тогда</p><pre><code class="cs">foreach (var i in CountDown(3))
    Console.WriteLine(i);</code></pre><p>Даст</p><pre><code>3
2
1
0
Finally!!!</code></pre><p><code>CountDown(3, stopAt: 1)</code><strong><em> </em></strong>выведет</p><pre><code>3
2
1
Finally!!!</code></pre><p>А <code>CountDown(3, failAt: 1)</code></p><pre><code>3
2
1
Unhandled exception. System.Exception: Inner failure at count = 1
   at TryFinally.Program.CountDown(Int32 count, Nullable`1 stopAt, Nullable`1 failAt)+MoveNext() in C:\Users\Admin\source\repos\TryFinally\TryFinally\Program.cs:line 63
   at TryFinally.Program.Main(String[] args) in C:\Users\Admin\source\repos\TryFinally\TryFinally\Program.cs:line 10
Finally!!!</code></pre><p>Ранний <code>break</code> <code>finally</code> не помеха:</p><details class="spoiler"><summary>Код</summary><div class="spoiler__content"><pre><code class="cs">foreach (var i in CountDown(3, failAt: 1))
{
    Console.WriteLine(i);
    break;
}</code></pre><pre><code>3
Finally!!!</code></pre></div></details><p>Грубо говоря</p><pre><code class="cs">foreach (var i in CountDown(3))
    Console.WriteLine(i);</code></pre><p>развернется в</p><details class="spoiler"><summary>Код</summary><div class="spoiler__content"><pre><code class="cs">var enumerator = CountDown(3).GetEnumerator();
try
{
    int i;
    while (enumerator.MoveNext())
    {
        i = enumerator.Current;
        Console.WriteLine(i);
    }
}
finally
{
    enumerator?.Dispose();
}</code></pre></div></details><p>и результат будет идентичен <code>foreach</code> и для <code>CountDown(3).GetEnumerator()</code>, и для <code>CountDown(3, stopAt: 1).GetEnumerator()</code>, и для <code>CountDown(3, failAt: 1).GetEnumerator()</code>, и для <code>break;</code> после <code>Console.WriteLine(i);</code>.</p><p>Если закомментировать <code>enumerator.Dispose();</code></p><details class="spoiler"><summary>Код</summary><div class="spoiler__content"><pre><code class="cs">var enumerator = CountDown(3, stopAt: 1).GetEnumerator();
try
{
    int i;
    while (enumerator.MoveNext())
    {
        i = enumerator.Current;
        Console.WriteLine(i);
        break;
    }
}
finally
{
    // enumerator.Dispose();
}</code></pre></div></details><p>то в выводе получим просто <code>3</code>, и можно предположить, что код блока <code>finally</code> метода <code>CountDown</code> вызывается в <code>enumerator.Dispose()</code>.</p><p>Но если также закомментировать и <code>break;</code>, то вывод будет:</p><pre><code>3
2
1
Finally!!!</code></pre><p>Если открыть сборку с методом с помощью ILSpy, метод примерно выглядит так:</p><details class="spoiler"><summary>Код</summary><div class="spoiler__content"><pre><code class="cs">IEnumerable&lt;int&gt; CountDown(int count, int? stopAt = null, int? failAt = null)
{
    try
    {
        while (true)
        {
            if (count &gt; -1)
            {
                yield return count;
                if (count != stopAt)
                {
                    if (count == failAt)
                    {
                        break;
                    }
                    count--;
                    continue;
                }
                yield break; // &lt;- triggers 'finally'
            }
            yield break; // &lt;- triggers 'finally'
        }
        throw new Exception(string.Format("Inner failure at {0} = {1}", "count", count));
    }
    finally
    {
        Console.WriteLine("Finally!!!");
    }
}</code></pre></div></details><p>И можно заметить, что код блока <code>finally</code> метода <code>CountDown</code> вызывается после <code>yield break;</code>. Один из них используется явно, а второй добавлен автоматически в конец метода компилятором.</p><p>А теперь выполним</p><pre><code class="cs">var enumerator = CountDown(3, failAt: 1).GetEnumerator();
try
{
    int i;
    while (enumerator.MoveNext())
    {
        i = enumerator.Current;
        Console.WriteLine(i);
    }
}
finally
{
    // enumerator.Dispose();
}</code></pre><p>и получим</p><pre><code>3
2
1
Unhandled exception. System.Exception: Inner failure at count = 1
   at TryFinally.Program.CountDown(Int32 count, Nullable`1 stopAt, Nullable`1 failAt)+MoveNext() in C:\Users\Admin\source\repos\TryFinally\TryFinally\Program.cs:line 66
   at TryFinally.Program.Main(String[] args) in C:\Users\Admin\source\repos\TryFinally\TryFinally\Program.cs:line 40
Finally!!!</code></pre><p>То есть исключение тоже запустило выполнение блока <code>finally</code>.</p><p>Таким образом, при использовании <code>try-finally</code> с <code>yield return</code>, блок <code>finally</code> выполняется:</p><ul><li><p> в  <code>enumerator.Dispose();</code></p></li><li><p>после исключения</p></li><li><p>и после <code>yield break;</code></p></li></ul><p>И не выполняется вовсе при невыполнении ни одного из этих условий.</p><p>Кстати</p><pre><code class="cs">var enumerator = CountDown(3, failAt: 1).GetEnumerator();
enumerator.Dispose();</code></pre><p>Все равно не запустит <code>finally</code>. Нужен хотябы один вызов <code>enumerator.MoveNext()</code>.</p>]]></description>
      <pubDate>Wed, 22 Dec 2021 14:33:31 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>03.07.2021 15:15:38 </title>
      <guid isPermaLink="true">https://habr.com/ru/companies/vdsina/articles/565032/#comment_23220806</guid>
      <link>https://habr.com/ru/companies/vdsina/articles/565032/#comment_23220806</link>
      <description><![CDATA[Спасибо, добрый человек. Прошел на одном дыхании. Но что-то подсказывает, что она вполне реиграбельна.]]></description>
      <pubDate>Sat, 03 Jul 2021 15:15:38 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>06.04.2021 20:41:00 </title>
      <guid isPermaLink="true">https://habr.com/ru/companies/englishdom/articles/551098/#comment_22893632</guid>
      <link>https://habr.com/ru/companies/englishdom/articles/551098/#comment_22893632</link>
      <description><![CDATA[Иногда замечаю странную запятую по типу <b><i>a, b, and c</i></b> в английских фразах в Duolingo. Всегда думал, что их программисты криво сделали составление предложений по шаблонам. (После примеров вроде «Мальчик ест мороженое с горчицей» или «Женщина разговаривает с конём» можно предположить, что они создаются скриптом.) А это, оказывается, на оксфордский манер.]]></description>
      <pubDate>Tue, 06 Apr 2021 20:41:00 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>11.01.2021 13:18:21 </title>
      <guid isPermaLink="true">https://habr.com/ru/articles/510994/#comment_22524028</guid>
      <link>https://habr.com/ru/articles/510994/#comment_22524028</link>
      <description><![CDATA[Ясно. Спасибо, что поделились. Для меня тема с викториной по промо-ролику — тревожный звонок. А по кодингу фидбэк сразу или «мы перезвоним»?]]></description>
      <pubDate>Mon, 11 Jan 2021 13:18:21 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>09.10.2020 14:21:20 </title>
      <guid isPermaLink="true">https://habr.com/ru/news/522682/#comment_22162526</guid>
      <link>https://habr.com/ru/news/522682/#comment_22162526</link>
      <description><![CDATA[Когда я учился, дневники были бумажные. И там была суббота, которая почти всегда пустовала. Вот живо представил, как администрация школы могла продавать эти рекламные площади местным ИП, а учителя бы объявления вклеивали. И как только они не додумались? Хоть сейчас предпринимательская мысль вперед шагнула.]]></description>
      <pubDate>Fri, 09 Oct 2020 14:21:20 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>05.10.2020 22:13:48 </title>
      <guid isPermaLink="true">https://habr.com/ru/articles/516286/#comment_22147800</guid>
      <link>https://habr.com/ru/articles/516286/#comment_22147800</link>
      <description><![CDATA[Для конечного результата не принципиально, т.к. имеем дело с коммутативностью.]]></description>
      <pubDate>Mon, 05 Oct 2020 22:13:48 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

  
    <item>
      <title>01.10.2020 20:27:16 </title>
      <guid isPermaLink="true">https://habr.com/ru/articles/516286/#comment_22133100</guid>
      <link>https://habr.com/ru/articles/516286/#comment_22133100</link>
      <description><![CDATA[Нет. Пример из реального кода. Типы назывались иначе и имели более сложное поведение и критерий слияния. От лишних деталей я абстрагировался для краткости, и чтобы не отвлекать внимание от главной цели (и NDA ненароком не нарушить). Вот и вышло так игрушечно.<br>
Исходный вариант метода — это, грубо говоря, наивная реализация. Чтобы такое написать, необязательно знать толк в извращениях.]]></description>
      <pubDate>Thu, 01 Oct 2020 20:27:16 GMT</pubDate>
      <dc:creator><![CDATA[]]></dc:creator>
    </item>
  

      

      

    
  </channel>
</rss>
