C# #区域/#结束区域vs子功能?

C# #区域/#结束区域vs子功能?,c#,visual-studio,C#,Visual Studio,您建议如何使用#region/#endregion?这在多大程度上应该取代使用子函数来澄清代码?一点也不 首先,#区域更像是将许多相关函数/成员分组到可折叠区域的一种方式。它们不打算将一个数千行的函数构造成多个部分。(就是说,如果你写一个很长的方法,你可以考虑用 >区域> /Code > s来构造它,那么你可能做了一些严重的错误。区域或不,那个代码是不可维护的。句号) 许多人争论说,它并没有真正的帮助,你应该考虑重写那些真正需要地区可以理解的课程。此外,区域往往隐藏令人讨厌的代码。#区域/#结束

您建议如何使用#region/#endregion?这在多大程度上应该取代使用子函数来澄清代码?

一点也不

首先,
#区域
更像是将许多相关函数/成员分组到可折叠区域的一种方式。它们不打算将一个数千行的函数构造成多个部分。(就是说,如果你写一个很长的方法,你可以考虑用<代码> >区域> /Code > s来构造它,那么你可能做了一些严重的错误。区域或不,那个代码是不可维护的。句号)

许多人争论说,它并没有真正的帮助,你应该考虑重写那些真正需要地区可以理解的课程。此外,区域往往隐藏令人讨厌的代码。

#区域
/
#结束区域
是一种对属于同一类的代码部分进行逻辑分组的方法。就个人而言,我倾向于将私有字段声明、属性、公共函数和私有函数分组


有时我会使用这些关键字对代码的某些部分进行分组,这些部分我需要经常查看和更新,例如,计算方法。

如果一个类中有多个“逻辑代码组”,则您的类违反了单一责任原则


整理一下,你就不再需要区域了。

区域在理论上看起来不错,但根据我的经验,这是一个经常被滥用的功能

程序员喜欢秩序;大多数人喜欢把东西整理成小盒子。它们将杂乱的代码、字段、属性、构造函数、方法、公共方法、内部方法、私有方法、帮助器方法、常量、接口实现和天知道的其他内容分组

我能想到的唯一更让我恼火的事情是使用分部类来隐藏复杂性

不管怎么说,尽管过度使用区域通常是隐藏不应该存在的混乱的信号,但我也看到好代码被它们淹没。我下载了一些由受人尊敬的程序员编写的开源项目。这些家伙正在写一些惊人的代码,但是,哦,这是什么

一个领域?一个野外区域! 两个属性?地产区! 一个构造器?一个构造函数区域! 一个私人方法?一个私有方法区域

我可以继续

直到今天,当我看到这一点时,我仍然感到震惊。在某些情况下,一个区域、一个空行、另一个空行和结束区域可能占用原始代码的5倍空间(5行带区域,1行不带区域)。它基本上是强迫症的一种形式;在编写软件的过程中,这些区域可能会吸引我们的秩序感,但实际上它们是无用的——纯粹的噪音。当我第一次开始写c#时,我也以这种方式滥用它们。但后来我意识到我的代码有多吵,每次打开文件时按ctrl-KL表示我做错了

当一个类实现了一个具有很多属性(例如用于数据绑定)的接口,或者甚至是一组用于实现某些相关功能的方法时,我可以理解这一点,但是对于所有的东西?。这毫无意义


我仍然时不时地使用区域,但是。。。我非常克制。

我发现使用区域完全可以的唯一情况是在下面的代码中。一旦我做对了,我就再也不想看那些常数了。事实上,我每天都使用这个类,我认为在过去四年中我唯一一次打开这个区域是在我需要用Python重新实现它的时候

我认为(希望、祈祷)该法典的情况是一个边缘案例。基于VB3类型声明的C++常数,定义了C++函数返回的COBOL数据结构的方式。是的,我把这个移植到Python。我很好。我很想学习Haskell,这样我就可以在其中重写Python代码,并希望有一天在OCaml中重新实现我的Haskell代码

    #region buffer_definition
    /*
        The buffer is a byte array that is passed to the underlying API.  The VB representation of
        the buffer's structure (using zero-based arrays, so each array has one more element than
        its dimension) is this:

        Public Type BUFFER_TYPE
            Method As String * 50
            Status As Integer
            Msg As String * 200
            DataLine As String * 1200

            Prop(49) As String * 100

            Fld(79) As String * 20
            Fmt(79) As String * 50
            Prompt(79) As String * 20
            ValIn(79) As String * 80
            ValOut(79) As String * 80
        End Type

        The constants defined here have the following prefixes:
            len = field length
            cnt = count of fields in an array
            ptr = starting position within the buffer
    */

    // data element lengths
    private const int len_method = 50;
    private const int len_status = 2;
    private const int len_msg = 200;
    private const int len_dataLine = 1200;

    // array elements require both count and length:
    private const int cnt_prop = 50;
    private const int len_prop = 100;

    private const int cnt_fld = 80;
    private const int len_fld = 20;
    private const int len_fmt = 50;
    private const int len_prompt = 20;
    private const int len_valIn = 80;
    private const int len_valOut = 80;

    // calculate the buffer length
    private const int len_buffer =
        len_method
        + len_status
        + len_msg
        + len_dataLine
        + (cnt_prop * len_prop)
        + (cnt_fld * (len_fld + len_fmt + len_prompt + len_valIn + len_valOut));

    // calculate the pointers to the start of each field.  These pointers are used
    // in the marshalling methods to marshal data into and out of the buffer.
    private const int PtrMethod = 0;
    private const int PtrStatus = PtrMethod + len_method;
    private const int PtrMsg = PtrStatus + len_status;
    private const int PtrDataLine = PtrMsg + len_msg;
    private const int PtrProp = PtrDataLine + len_dataLine;
    private const int PtrFld = PtrProp + (cnt_prop * len_prop);
    private const int PtrFmt = PtrFld + (cnt_fld * len_fld);
    private const int PtrPrompt = PtrFmt + (cnt_fld * len_fmt);
    private const int PtrValIn = PtrPrompt + (cnt_fld * len_prompt);
    private const int PtrValOut = PtrValIn + (cnt_fld * len_valIn);

    [MarshalAs(UnmanagedType.LPStr, SizeConst = len_buffer)]
    private static byte[] buffer = new byte[len_buffer];

    #endregion

我认为函数应该只用于可重用代码。这就是他们设计的目的。没有什么比看到为某个只调用一次的对象创建函数更让我烦恼的了

使用一个区域


如果你需要做500行,那么输入500行。如果你想整理它,使用一个区域,如果有任何可重用的东西,那么使用一个函数

完全同意。我个人讨厌区域,因为它们隐藏了代码。我还为接口实现配置了自定义模板,以便Visual Studio不会自动插入
#接口成员
。完全同意。每种方法都应该尽可能适合打印页面,将长度隐藏在#区域是一种很糟糕的方法。我也同意100%。如果它需要区域,它也需要重构,因为区域不是正确结构的替代品,并且使用不当,可能会隐藏问题。话虽如此,它们对于组织结构合理的代码以便于阅读仍然很有用。只有在没有它们的情况下(认真地说)才能使用区域,这只是为了吸引眼球。就个人而言,我不喜欢折叠代码,因为它隐藏了我感兴趣的代码:因此,您不会认为属性、构造函数和方法是逻辑可分组的吗?我认为他是指按功能分组。此外,如果您有足够的构造函数、方法或属性,需要将其折叠到区域中,则类可能太大。不一定,但通常情况就是这样。我最近开始比以前更频繁地分解类,代码变得更具可读性和可用性,尽管它以前一直工作得很好。@Dan-确实如此。他们是同一个班级的成员。如果你有这么多的产品,把它们包装成区域是有意义的,你需要重新考虑你的设计。我讨厌区域。为什么人们觉得他们需要将代码隐藏在#区域块中?