Intereting Posts
Применить фильтрацию для создания выпадающего списка SendMessage / SC_MONITORPOWER не включит монитор при запуске Windows 8 Шаблон блокировки для правильного использования .NET MemoryCache System.Threading.Timer не срабатывает через некоторое время Как выполнять код в определенное время каждый день? DataGridView – когда я нажимаю Enter, он переходит к следующей ячейке Извлечение записей по дате с использованием только частичного сравнения дней с использованием nhibernate Как вы можете обращаться к значкам из файла Multi-Icon (.ico), используя индекс в C # Как показать длинные номера в Excel? DynamicMethod намного медленнее, чем скомпилированная функция IL Создавать пользователь / admin по умолчанию при инициализации сайта – Identity Как показать MessageBox с помощью флажка? Мне нужна альтернатива `Assembly.GetEntryAssembly ()`, которая никогда не возвращает null Как определить исходный IP-адрес многоадресного пакета в C #? Что такое метод, если вы не используете идентификатор доступа?

Когда вы используете область без инструкции в C #?

Совсем недавно я узнал, что вы можете сделать это на C #:

{ // google string url = "#"; if ( value > 5 ) url = "http://google.com"; menu.Add( new MenuItem(url) ); } { // cheese string url = "#"; // url has to be redefined again, // so it can't accidently leak into the new menu item if ( value > 45 ) url = "http://cheese.com"; menu.Add( new MenuItem(url) ); } 

вместо того, чтобы:

  string url = "#"; // google if ( value > 5 ) url = "http://google.com"; menu.Add( new MenuItem(url) ); // cheese url = "#"; // now I need to remember to reset the url if ( value > 45 ) url = "http://cheese.com"; menu.Add( new MenuItem(url) ); 

Это может быть плохим примером, который можно решить многими другими способами.

Существуют ли какие-либо шаблоны, где функция «scope without statement» является хорошей практикой?

    Если вы спросите, почему они реализовали эту функцию?

    Я разработал свой собственный язык, и я обнаружил, что синтаксис «scope without of statement» очень легко проникает в грамматику. Это побочный эффект, если вы будете, при написании грамматики, которая просто работает красиво и легко читается .

    На моем языке у меня такая же функциональность, и я никогда не «специально» для нее явно – я получил ее бесплатно . Я никогда не садился за стол и думал: «О, не было бы здорово иметь такую« особенность »?». Хек – сначала я даже не знал, что моя грамматика допускает это.

    ‘{}’ – это «составной оператор», потому что это упрощает синтаксис для всех мест, которые вы хотите использовать (условные, тела циклов и т. д.) … и потому, что это позволяет вам оставить фигурные скобки, когда одно утверждение («if (a <10) ++ a;» и тому подобное).

    Тот факт, что он может использоваться везде, где может появляться заявление, попадает прямо из этого; это безопасно, и иногда полезно, как говорили другие ответы. «Если он не сломался, не исправляй его. – Кешлам.

    Таким образом, вопрос заключается не столько в том, «зачем они его реализовали», сколько в том, «почему они не запретили это / почему они это разрешили?»

    Могу ли я запретить эту конкретную функциональность на моем языке? Конечно, но я не вижу причин – это будет дополнительная стоимость для компании.

    Теперь приведенная выше история может быть или может быть неверной для C #, но я не разрабатывал язык (и я не являюсь разработчиком языка), поэтому трудно сказать, почему именно, но я думал, что я бы упомянул об этом в любом случае.

    Та же функциональность есть в C ++, которая фактически имеет некоторые варианты использования – она ​​позволяет дефинитивно запускать финализатор объекта, если объект выходит за пределы области действия, хотя это не относится к C #.


    Тем не менее, я не использовал этот специфический синтаксис за 4 года работы C # ( embedded-statement -> block , когда речь шла о конкретных терминах), и я не видел, чтобы он использовался где угодно. Ваш пример – попросить рефакторировать методы.

    Взгляните на грамматику C #: http://msdn.microsoft.com/en-us/library/aa664812%28v=vs.71%29.aspx

    Кроме того, как сказал Джеппе, я использовал синтаксис «{}», чтобы каждый блок case в конструкции «switch» имел отдельную локальную область:

     int a = 10; switch(a) { case 1: { int b = 10; break; } case 2: { int b = 10; break; } } 

    Одно использование, которое я считаю приемлемым во многих случаях, заключается в том, чтобы заключить каждый раздел switch оператора switch в локальную область.


    Позднее добавление:

    Блоки локальной видимости { ... } присутствующие в источнике C #, не кажутся релевантными для полученного байт-кода IL. Я попробовал этот простой пример:

     static void A() { { var o = new object(); Console.WriteLine(o); } var p = new object(); Console.WriteLine(p); } static void B() { var o = new object(); Console.WriteLine(o); var p = new object(); Console.WriteLine(p); } static void C() { { var o = new object(); Console.WriteLine(o); } { var o = new object(); Console.WriteLine(o); } } 

    Это было скомпилировано в режиме Release (оптимизация включена). Полученный IL в соответствии с IL DASM:

     .method private hidebysig static void A() cil managed { // Code size 25 (0x19) .maxstack 1 .locals init ([0] object o, [1] object p) IL_0000: newobj instance void [mscorlib]System.Object::.ctor() IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: call void [mscorlib]System.Console::WriteLine(object) IL_000c: newobj instance void [mscorlib]System.Object::.ctor() IL_0011: stloc.1 IL_0012: ldloc.1 IL_0013: call void [mscorlib]System.Console::WriteLine(object) IL_0018: ret } // end of method LocalScopeExamples::A 

     .method private hidebysig static void B() cil managed { // Code size 25 (0x19) .maxstack 1 .locals init ([0] object o, [1] object p) IL_0000: newobj instance void [mscorlib]System.Object::.ctor() IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: call void [mscorlib]System.Console::WriteLine(object) IL_000c: newobj instance void [mscorlib]System.Object::.ctor() IL_0011: stloc.1 IL_0012: ldloc.1 IL_0013: call void [mscorlib]System.Console::WriteLine(object) IL_0018: ret } // end of method LocalScopeExamples::B 

     .method private hidebysig static void C() cil managed { // Code size 25 (0x19) .maxstack 1 .locals init ([0] object o, [1] object V_1) IL_0000: newobj instance void [mscorlib]System.Object::.ctor() IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: call void [mscorlib]System.Console::WriteLine(object) IL_000c: newobj instance void [mscorlib]System.Object::.ctor() IL_0011: stloc.1 IL_0012: ldloc.1 IL_0013: call void [mscorlib]System.Console::WriteLine(object) IL_0018: ret } // end of method LocalScopeExamples::C 

    Выводы:

    • Локальные объявления области не существуют в какой-либо форме в байт-коде IL.
    • Компилятор C # будет выбирать новые имена для локальных переменных, которые в противном случае были бы конфликтующими (вторая из переменных o в методе C ).
    • Люди, которые чувствуют (см. Другие ответы и комментарии к вопросу), что сборщик мусора может выполнить свою работу раньше, когда они вводят локальную область в источник C #, ошибочны.

    Я также попытался скомпилировать это в режиме отладки (без оптимизации). Начало и конец локальной области видимости отображаются только как команда nop («Нет операции»). В некоторых случаях две идентично названные локальные переменные из разных локальных областей были сопоставлены с одной и той же локальной переменной в IL, например, с использованием метода C # с именем C выше. Такое «объединение» двух переменных возможно только в том случае, если их типы совместимы.

    Вы можете использовать {} для переименования имен переменных (даже для разных типов):

     { var foo = new SomeClass(); } { Bar foo = new Bar(); // impairs readability } 

    Однако перепрофилирование переменных таким образом будет путать читаемость.

    Поэтому вместо того, чтобы использовать «незапрашиваемый» блок видимости без предшествующего утверждения, в большинстве случаев код вместо этого должен быть реорганизован на отдельные функции соответственно.

    редактировать

    ИМО, в любое время, когда возникает необходимость императивно сбросить местные изменчивые значения переменных или перепрофилировать их для дополнительных или альтернативных проблем, это признак запаха. например, исходный код может быть реорганизован как:

     menu.Add( value > 5 ? new MenuItem("http://google.com") : new MenuItem("#")); menu.Add( value > 45 ? new MenuItem("http://cheese.com") : new MenuItem("#")); 

    Который, я считаю, передает намерение, без риска того, что # резерв не применяется, и без необходимости наличия явных локальных переменных переменных для сохранения состояния.

    (или new MenuItem(value > 45 ? "http://cheese.com" : "#") или создать перегрузку MenuItem со значением по умолчанию # или переместить создание MenuItem в заводский метод и т. д.).

    редактировать
    Re: Сфера действия не влияет на продолжительность жизни

    Область применения может использоваться в рамках метода ограничения продолжительности жизни дорогостоящих объектов

    В моем первоначальном сообщении неправильно указано, что локальная область может использоваться для воздействия на продолжительность жизни объектов. Это неверно, как для версий DEBUG и для RELEASE , и независимо от того, перераспределено ли имя переменной или нет, как продемонстрировано parsingкой Jeppe’s IL и этими модульными тестами здесь . Спасибо Джеппе за это. Кроме того, Лассе подчеркивает, что даже без явного выхода из сферы действия переменные, которые больше не используются, будут иметь право на garbage collection в assemblyх релизов.

    TL; DR Хотя использование незапрошенной области видимости может помочь логическому использованию области переменных для человека, это не влияет на то, становится ли объект доступным для сбора, в рамках того же метода.

    т.е. в приведенном ниже коде, определение области обзора и даже повторное назначение переменной foo ниже абсолютно не влияют на продолжительность жизни.

     void MyMethod() { // Gratuituous braces: { var foo = new ExpensiveClass(); } { Bar foo = new Bar(); // Don't repurpose, it impairs readability! } Thread.Sleep(TimeSpan.FromSeconds(10)); GC.Collect(); GC.WaitForPendingFinalizers(); < -- Point "X" } 

    В точке X:

    • В сборке DEBUG ни одна из переменных foo будет собрана, несмотря на хакерские попытки побудить GC сделать это.
    • В сборке RELEASE оба foos были бы пригодны для сбора, как только они не понадобятся, независимо от области действия. Время сбора, конечно, должно быть предоставлено на собственные устройства.

    Этот шаблон практически не влияет на время выполнения C #, поэтому это чисто эстетическая вещь (сравните с C ++, где мы регулярно используем этот шаблон с RAII для охвата таких вещей, как блокировки).

    Если у меня есть два полностью несвязанных блока кода, я иногда буду использовать их таким образом, чтобы на 100% понять, какие переменные программист должен держать в голове как «потенциально модифицированные в предыдущем блоке». Он заполняет пробел между on- big-code-block и изолированные функции, я могу использовать некоторые переменные, а не другие.

    Я также буду использовать это для автоматического создания кода. Часто бывает намного проще работать с такими плагинами, не беспокоясь о взаимодействиях.

    Когда я это использую, я стилистически хотел бы поставить комментарий перед каждым блоком, грубо говоря, куда будет идти инструкция if , объясняя, что сделает блок. Я считаю, что полезно избегать других разработчиков, думающих «похоже, что раньше был stream управления, но кто-то его подкачал». В этом случае это может быть немного перебор, но вы получите идею:

     // Add a menu item for Google, if value is high enough. { string url = "#"; if ( value > 5 ) url = "http://google.com"; menu.Add( new MenuItem(url) ); } // Add a menu item for Cheese, if the value is high enough { // cheese string url = "#"; if ( value > 45 ) url = "http://cheese.com"; menu.Add( new MenuItem(url) ); } 

    Как было сказано ранее, в C # это чисто стилистическая. Не стесняйтесь использовать свой собственный стиль, где это имеет смысл.

     { string f = "hello"; } 

    Просто выглядит странно.

    Очевидно, что им нужны методы:

     private void hmm() {} 

    И инструкции switch:

     switch(msg) { case "hi": // do something break; // ... } 

    И даже если для foreach, в то время как заявления …

     if(a == 1) { bool varIsEqual = true; isBusy = true; // do more work } 

    Но если у вас есть только 1 оператор в цикле или операторе if, вам не нужны скобки:

     if("Samantha" != "Man") msg = "Phew!";