【问题标题】:Simple C# Noop Statement简单的 C# Noop 语句
【发布时间】:2011-10-18 23:33:16
【问题描述】:

什么是 C# 中不需要实现方法的简单 Noop 语句? (不过,内联/Lambda 方法是可以的。)

我当前的用例:我想占用 try-catch 的 catch-block,这样我就可以在调试时单步执行并检查异常。
我知道无论如何我都应该处理/记录异常,但这不是本练习的重点。

【问题讨论】:

  • 你不能把断点放在catch块的关闭}上吗?
  • 如果您想查看异常,也可以在catch (...) 上中断并执行一次。
  • 这对我来说只是闻起来很糟糕。几乎所有建议都会导致神秘的构造或​​异常隐藏代码。我想到的问题是:“为什么只对调试时的异常感兴趣?”
  • @Protector:也许执行正在滑过} 的薄弱边缘。您可以尝试使用 catch (Exception e) {{{{{{{{{{ }}}}}}}}}} 创建更硬的握持。
  • @Protector one 您使用的是发布版本还是调试版本?在发布版本中,catch (Exception e) {} 将折叠为 catch {}

标签: c# noop


【解决方案1】:

如果你真的想要noop,那么这定义了一个不做任何事情的无名动作,然后调用它,导致什么都没有发生:

((Action)(() => { }))();

【讨论】:

  • 你喜欢这个,但你不喜欢 Noop 方法?为什么?
  • @David Heffernan,因为当我决定丢弃它时,现在只有一行要删除。懒惰的?也许吧。
  • @Protector one 为什么你需要删除 Noop 方法?我原以为懒惰(在许多方面都是一个令人钦佩的特质)会让你更喜欢写 Noop(); 而不是 ((Action)(() => { }))(); 这对我来说似乎有点重。
  • 还是方法调用。
  • @David Heffernan:如果你只从事一个项目,那么写一次 Noop/0 会更好,当然。如果您正在处理多个代码库,我宁愿只记住一个(相对)简单的语句。
【解决方案2】:

c#中标准的空语句/noop操作是

;

如:

if (true)
    ;

(relevant documentation)

这专门针对您的用例(只需在 ; 行上放置一个断点,或以其他方式进入它),是最小的,并且仅出于此目的由环境直接支持(所以即使您是做复杂的事情,比如查看编译后的源代码,你不会有任何额外的噪音/等等..需要担心编译器/优化器/等等...) - 并且有发出警告的额外好处,如提醒您在完成调试/推送到生产时将其从代码中清除

【讨论】:

  • IMO 也是正确答案。我会添加类似// NOOP 的评论,让我知道这是故意的。
  • 单个; 将被编译掉,所以从行为的角度来看,它不是一个问题。 (它应该什么,而不是be什么。)
【解决方案3】:

如果你想闯入该方法,你可以硬编码一个断点:

System.Diagnostics.Debugger.Break();

或者,如果您不在发布模式下编译,以下行将发出您可以中断的 IL:

var a = 1;

您还可以编写特定于您的机器的 Debug.Break():

[Conditional("DEBUG")]
[Obsolete("Please remove me before checkin.")]
public static void Break()
{
    #IF DEBUG
    if (Dns.GetHostName() == "PROTECTORONE")
        Debugger.Break();
    #ENDIF
}

请注意,由于[Conditional("DEBUG")],该方法不会在 RELEASE 构建期间在调用站点中被调用。

【讨论】:

  • @Protector one 尝试一下 Break(),它是临界黑客。
  • @Protector one - 现在它甚至会警告您在构建期间正在使用它;并且它不会进入 RELEASE 构建(C# 编译器不会调用该方法)。
【解决方案4】:

你可以编写一个什么都不做的函数。

public static void Noop()
{
}

【讨论】:

  • 这违反了“无方法”规则。
  • @Protector “无方法”规则是任意的,我会直接忽略它
  • @David:这不是任意的,因为它是问题的先决条件之一。人们可以质疑它是否是一个明智的先决条件,但如果没有这个先决条件,我认为这个问题甚至不存在。因此,答案应该要么反对先决条件给出与之匹配的答案——而不是仅仅违反先决条件,就好像它没有被说明一样.
  • @Jon 同意反对会改善这个答案
  • 如果您正在调试发布版本,那么这将得到优化。
【解决方案5】:

C# 中的标准空语句/noop 操作是 ;,如 if (true) ;
- 蓝莓地

但是使用该标准 ; 作为 if 语句的分支会使 MS Visual Studio 2010 显示警告:“可能错误的空语句”。 (警告 CS0642,虽然 VS2010 没有告诉我,也没有链接到警告的实际帮助。)

更糟糕的是, MSDN C# 语言规范没有提到 实际上编码该空语句作为 if 语句的分支会引发警告 CS0642“可能错误的空语句”。 (警告,因为它是“错误的形式”,可能会模棱两可。)

更糟糕的是,看起来 VS2010 没有办法巧妙地抑制单个警告。我必须在行之前插入#pragma warning disable CS0642,在之后插入[可选]#pragma warning disable CS0642。对我来说,这比警告更丑陋。我最好使用{ } 代替;。 (我可能会使用不那么难看的覆盖。)

我在这里寻找“C# no-op”,因为我想要一个替代“空语句”的方法,以消除该警告。我不需要检查站。我只想要一个做-[绝对]-没有像“空语句”那样模棱两可的事情。

替代方案不得引发 SOME OTHER 警告。 int u; 不好,因为它会引发警告“变量 'u' 已声明但从未使用”。 int u = 0; 不好,因为它会引发警告“已分配变量 'u' 但从未使用过它的值”。

如果将noop;(或类似的)添加为明确的空语句(不是宏定义),那就太好了。

如果noop();(或类似的)是一个具有空主体的函数(当编译器内联它时它会完全消失),那就太好了。

当分支只有一个语句时,我经常省略周围的{} LINES,因为它们不需要,它们会垂直拉伸代码,使其更难阅读。语言中的不一致之处在于,当 {} LINES 围绕 ZERO 语句时,我不能省略它们。我可以将这两行压缩到同一行上的{ },但这是不一致的。我认为在线上的; 是最简洁的解决方案,它不应该以[未说明的]“不良形式”为由发出警告。我认为警告 CS0642 应该默认为 OFF。我认为以下代码应该是可以接受的:

if (condition1)
  action1;
else if (condition2)
  ;  // (do nothing)
else if (condition3)
  action3;
else if (condition4)
  ;  // (do nothing)
else if (condition5)
  action5;
else
  action99;

(我很遗憾无法将其写为评论,因为我还没有“有 50 个声望可以评论”。现在我可以评论了,2K 字节,1.5K 字节的评论太长了,所以它一直在这里。)

【讨论】:

    【解决方案6】:

    你可以写:

    catch {
        ;
    }
    

    带有单个分号的空语句是 C# NOOP。

    【讨论】:

      【解决方案7】:

      怎么样:

      GC.KeepAlive(e);
      

      e 是哪里的异常变量?

      (我没有尝试在 catch 声明本身上设置断点。感觉您应该能够这样做,正是出于这个原因。但它是否有效是另一回事。)

      或者更隐晦地说,假设您已经有了 System.LINQ 的 using 指令:

      "".AsEnumerable();
      

      【讨论】:

      • 但是,根据这里一位非常聪明的人的评论,“这将封装任何值类型的值”:stackoverflow.com/questions/6611844/…
      • 啊,是的,很尴尬……但如果我也能在更一般的情况下使用这个 noop 就好了。
      • @Jon Skeet 在调试中,e 的生命周期被延长到方法结束,那为什么要 KeepAlive 呢?
      • @Felice:正是因为它没有效果。问题是 要求 一种不做任何事情的简单方法。我认为GC.KeepAlive 非常适合该法案。
      • @Protector one:如果你想要一个更通用的无操作,可能值得为它编写一个单独的方法。
      【解决方案8】:

      除了直接回答问题的答案。


      如果你只是想中断,那么你总是可以将断点放在catch 块的开头{ 或关闭} 上。

      【讨论】:

      • 这对我不起作用……当我这样做时,Visual Studio 从不初始化 Exception 变量。
      • 尝试打开{ 大括号。我可以在一个空的 catch 块中看到异常。当然,您确实需要写catch(Exception e),并忍受未使用的警告。
      • 好的,所以当您将构建配置设置为调试时,这工作。对不起。
      【解决方案9】:

      我知道这是一个老问题,从技术上讲,这个答案与提问者的用例无关。但是,CIL 中有一条 NOOP 指令,即nop。作为一个实验,采用以下 CIL 应用程序。

      .assembly extern mscorlib {}
      
      .assembly Test
      {
          .ver 1:0:1:0
      }
      .module test.exe
      
      .method static void main() cil managed
      {
          .maxstack 1
          .entrypoint
      
          nop
          nop
          nop
          nop
      
          ret
      }
      

      如果你编译应用程序,然后使用 ILSpy 之类的工具将其反编译为 C#,这是 main() 方法的内容:

      static void main()
      {
      }
      

      如您所见,那里什么都没有。但是,如果我们想验证 CIL 编译器没有优化这些 nop 语句,我们可以在 ILSpy 中以反编译的 IL 代码查看我们的应用程序,这就是我们看到的 main 方法:

      .method static privatescope 
          void main$PST06000001 () cil managed 
      {
          // Method begins at RVA 0x2050
          // Code size 5 (0x5)
          .maxstack 1
          .entrypoint
      
          IL_0000: nop
          IL_0001: nop
          IL_0002: nop
          IL_0003: nop
          IL_0004: ret
      } // end of method '<Module>'::main
      

      CIL 肯定会将nop 指令编译到程序集中。由于 C# 没有此指令的实现,因此这些 nop 命令不会显示在反汇编的 C# 代码中。

      我没有 Reflector 的许可证,但我想如果你用 Reflector 反编译这些二进制文件,你会得到类似的 C# 输出。

      【讨论】:

        【解决方案10】:

        为什么要过度设计这个?

        var x = 0;
        

        工作得很好:)

        【讨论】:

        • 这也是我的直觉,但由于变量未使用,Visual Studio 会对此方法发出警告。我最终使用了带有分号 => 的@blueberryfields 技巧; //noop
        • 任何时候我都这样做了,我总是在它之后添加x++;。我想确保编译器不会把它洗掉。
        【解决方案11】:

        C# 中的 NOP 是存在的,就像在 C 中一样,是 ';',它的正确定义是“空语句”,但是对于您想要的用法,足以将断点放入关闭捕获支架... 不需要保持活动状态,因为当附加调试器时,方法中对象引用的生命周期会延长到方法的末尾。所以你只需要写

        catch(Exception exception)
        {
        }
        

        将断点放在右括号上,查看异常内容。

        【讨论】:

        • 实际上,这两种解决方案似乎都不适合我!如果我使用;,Visual Studio 会自动跳过它。
        • @Protrector one,它应该会根据您的需要跳过“}”上的制动点。
        • 我不会真的给;打电话。 nop 是什么都不做的事情,但一个单独的 ; 什么都不是 :)
        • @Porges 你说得对,它被很好地定义为“The Empty Statement”
        • 为我工作,断点到块的末尾,调试器停在那里。
        【解决方案12】:

        您是否正在尝试调试发布(优化)版本?通常是优化器删除未引用的变量和空块。

        两种解决方案:

        • 在调试版本中进行调试。
        • catch 本身上放置一个断点并使用 $exception(由调试器创建以引用运行中的异常)在 Locals 工具窗口中。

        【讨论】:

        • 啊,本地窗口技巧很不错!至少解决了我目前的问题。
        • 一开始我不明白你的“Debug in a debug build”这句话,但这确实是我应该做的。
        【解决方案13】:

        这是对@AHM 答案的补充,因为我想要一种简单的方法来执行 NOOP 以进行调试(与 AB PLC CompactLogix 通信并遇到错误,因为 C# 中的 C++ 库 DLL 导入仅在反汇编中真正可见)。

        我拿了单线

        ((Action)(() => { }))();
        

        并将其放入名为 noop.sn-p 的 sn-p 中,然后将其放入名为 My Code Snippets 的文件夹中。
        (工具 -> 代码片段管理器 -> 位置) OR Chord (Ctrl+K,Ctrl+B)

        <?xml version="1.0" encoding="utf-8" ?>
        <CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
            <CodeSnippet Format="1.0.0">
                <Header>
                    <Title>noop</Title>
                    <Shortcut>noop</Shortcut>
                    <Description>Code snippet to inject an assembly (x86) equivalent of the NOOP command into the code's disassembly.</Description>
                    <Author>Jay Whaley</Author>
                    <SnippetTypes>
                        <SnippetType>Expansion</SnippetType>
                    </SnippetTypes>
                </Header>
                <Snippet>
                    <Code Language="csharp">
                    <![CDATA[// Forces a psuedo NOOP in disassembly
                        ((Action)(() => { }))();
                    $end$]]>
                    </Code>
                </Snippet>
            </CodeSnippet>
        </CodeSnippets>
        

        这有助于使其成为一种快速使用快捷方式,以防低级通信变得混乱,并要求这是一种常见的调试策略。实际生成的程序集如下,但是有some posts about how to use actual assembly inline in C#.

        【讨论】:

          【解决方案14】:

          在考虑了各种选项后,我认为一对空括号和一个简洁的注释是最简洁的。没有额外的代码、自文档化,而且比单个分号更明显。

          {/* Noop */}
          

          例如

          if (String.IsNullOrEmpty(value))
              {/* Noop */}
          else if (Data.ContainsKey(key))
          

          【讨论】:

            【解决方案15】:

            可靠的解决方案

            try
            {
               blablablablaStatemnt();
            }
            catch(Exception ex)
            {
                #IF DEBUG
                   Debugger.Break();
                #END IF
            }
            

            就这么简单!

            否则

            断点

            很有用;

            【讨论】:

              【解决方案16】:

              很多很棒的解决方案!我的目标是:

              _ = "";
              

              【讨论】:

              • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
              【解决方案17】:

              我很喜欢这个,只是因为它会让遇到它的人感到困惑:

              catch (SomeException e)
              {
                  lock(e);
              } 
              

              【讨论】:

              • 无论谁来维护都会惊叹于您的创造力和独创性 - 说真的,用代码混淆人们根本不是要走的路。这正是我们这些天试图通过人类可读编码摆脱的事情之一......
              • @GrantThomas 很确定他很幽默。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-02-22
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-02-22
              • 1970-01-01
              相关资源
              最近更新 更多