【发布时间】:2010-01-20 17:04:41
【问题描述】:
您如何推荐使用#region / #endregion?那应该在多大程度上取代使用子函数来澄清你的代码?
【问题讨论】:
-
我讨厌#region。为什么人们觉得他们需要将代码隐藏在#region 块中?
标签: c# visual-studio
您如何推荐使用#region / #endregion?那应该在多大程度上取代使用子函数来澄清你的代码?
【问题讨论】:
标签: c# visual-studio
一点也不。
首先,#regions 更多是一种将许多相关功能/成员分组到可折叠区域的方式。它们不旨在将单个多行函数构造成多个部分。 (话虽这么说,如果您编写的单个方法太长以至于您考虑使用#regions 对其进行结构化,那么您可能做错了严重的事情。无论区域与否,该代码都将无法维护。期间。)
然而,许多人争辩说,它并没有真正的帮助,并且您应该考虑重写实际上需要区域的类以便于理解。此外,区域往往会隐藏讨厌的代码。
【讨论】:
#region ISomeInterface Members。
#region / #endregion 是一种对属于同一类的代码进行逻辑分组的方法。就个人而言,我倾向于将私有字段声明、属性、公共函数和私有函数分组。
有时我会使用这些关键字对代码的某些部分进行分组,这些部分我需要经常维护和更新,例如计算方法。
【讨论】:
如果您在一个类中有多个“逻辑代码组”,则您的类违反了单一职责原则。
解决这个问题,您就不再需要区域了。
【讨论】:
区域在理论上看起来不错,但根据我的经验,这是一个经常被滥用的功能。
程序员喜欢秩序;大多数人喜欢把东西整理成小盒子。它们将混乱的代码、字段、属性、构造函数、方法、公共方法、内部方法、私有方法、辅助方法、常量、接口实现和天知道还有什么组合在一起。
我能想到的唯一让我更恼火的是使用部分类来隐藏复杂性。
无论如何,虽然过度使用区域通常是隐藏不应该存在的混乱的迹象,但我也看到了它们淹没了好的代码。我下载了一些由受人尊敬的程序员编写的开源项目。这些家伙正在编写一些惊人的代码,但是,哦,这是什么?
一个领域?野区! 两个属性?地产区! 一个构造函数?建设者地区! 一种私有方法?私有方法区域!
我可以继续。
直到今天,当我看到这个时,我仍然感到震惊。在某些情况下,一个区域、一个空行、另一个空行和结束区域可以占用原始代码的 5 倍空间(5 行有区域,1 行没有)。它基本上是强迫症的一种形式。在编写软件的过程中,这些区域可能会吸引我们的秩序感,但实际上它们是无用的——纯粹的噪音。当我第一次开始编写 c# 时,我也以这种方式滥用它们。但后来我意识到我的代码有多么嘈杂,每次打开文件时都按 ctrl-k l 表明我做错了。
当一个类实现一个具有很多属性的接口(例如用于数据绑定)或什至一组用于实现某些相关功能的方法时,我可以理解它,但对于一切?。没有意义。
我仍然时不时地使用区域,但是...我非常克制。
【讨论】:
我觉得使用区域完全没问题的唯一情况是在下面的代码中。一旦我做对了,我就再也不想再看那些常数了。事实上,我每天都在使用这个类,而且我认为在过去四年中我唯一一次解开这个区域是当我需要用 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 行。如果你想整理它使用一个区域,如果有任何可重用的东西,那么使用一个函数。
【讨论】: