要强调还是不强调,这就是问题所在


130

如果二进制版本将由其他框架语言使用,则在C#中不给私有字段加下划线前缀是否存在任何问题?例如,由于C#区分大小写,因此您可以调用字段“ foo”和公共属性“ Foo”,并且效果很好。

这对不区分大小写的语言(例如VB.NET)有什么影响,如果名称只能用大小写区分,会不会存在CLS兼容(或其他)问题?


18
下划线前缀BTW的目的不是要处理大小写问题。在读取代码时,它可以轻松直观地区分字段和本地。我将在C#和VB中使用它。
尼尔·休伊特

2
@NeilHewitt:好的,它还可以防止函数参数与成员变量冲突,成员变量要求每个成员变量前面都带有this,这很烂。编辑:我只是回应了一个四岁的评论...
Ed S.

只是为了清楚起见,官方标准_camelCase(只读青睐)github.com/dotnet/corefx/blob/master/Documentation/...
克里斯Marisic

我更喜欢_camelCase作为私人后备店。即:私有文件,其中包含通过属性分配和访问的数据。我不喜欢自动属性,因为它们无法在类定义中初始化为已知值,并且如果我想在设置器中产生副作用,则需要显式声明的后备存储。不幸的是,当我在c#编辑器中使用^ R ^ E时,这会被重构,因此我每次都必须将其重新添加。
TomXP411 '19

Answers:


46

它不会有任何作用。

编写符合CLS的库的建议部分是不会有两个公共/保护的实体只有大小写不同,例如,你应该

public void foo() {...}

public void Foo() {...}

您描述的内容没有问题,因为私有项目对图书馆用户不可用


1
即使没有任何效果,这仍然是我不满意的约定-因为如果它们仅因情况而异,那么这就是造成混乱的秘诀。如果唯一的区别是初始资金,那么容易误读或输入错误。
克里斯

2
PS个人而言,我不会强调C#。对我来说,这是个人喜好,而不是宗教信仰
Binary Worrier

1
我已经做了两种方式,我想根据自己的知识做出决定,
一劳永逸

46
我正在使用下划线。将它们与参数和局部变量区分开来比较容易。
Rinat Abdullin 09年

4
我仅将_用于私有字段,但是由于3.5 auto属性,我几乎从来没有私有字段。通常,只有在我对非基本类型实现延迟加载时,才有一个私有字段。
克里斯·马里西克

278

重要更新(2016年4月12日):

引起我们注意的是.NET CoreFX团队的内部标准坚持使用下划线符号,而未给出任何原因的见解。但是,如果我们在规则#3密切关注它变得明显,有制度_t_s_那建议前缀为什么_选择摆在首位。

  1. 我们_camelCase用于内部和私有字段,并在可能的情况下使用只读。带有的实例字段前缀,带有的_静态字段前缀s_和带的线程静态字段前缀t_。在静态字段上使用时,readonly应紧随其后static(即static readonly不是readonly static)。
  2. this.除非绝对必要,否则我们将避免。

因此,如果您就像.NET CoreFX团队一样在处理一些性能关键的多线程系统级代码,那么强烈建议您:

  • 遵守他们的编码标准
  • 使用下划线符号和
  • 不要再看这个答案了

否则请继续阅读...

原始答案:

首先让我们就我们在说什么达成一致。问题是,如果可见性修改器允许,我们如何从非静态方法和类/子类的构造函数中访问实例成员。

下划线符号

  • 建议您在专用字段名称中使用“ _”前缀
  • 它还说除非绝对必要,否则不要使用“ this”

这个符号

  • 建议您始终使用“ this”。访问任何实例成员

为什么存在这个符号?

因为你就是这样

  • 当它们共享相同的名称时,从字段中区分出一个参数
  • 确保您正在当前实例的上下文中工作

public class Demo
{
   private String name;
   public Demo(String name) {
       this.name = name;
   }
}

为什么下划线符号存在?

有些人不喜欢键入“ this”,但是他们仍然需要一种区分字段和参数的方法,因此他们同意在字段前面使用“ _”

public class Demo
{
   private String _name;
   public Demo(String name) {
      _name = name;
   }
}

有人可能认为这只是个人品味的问题,两种方法的优劣都同样。但是,在某些方面,该符号要优于下划线符号:

明晰

  • 下划线符号使名称混乱
  • 此符号使名称完整无缺

认知负荷

  • 下划线符号是不一致的,它使您以特殊的方式对待字段,但是每次需要询问自己是否需要属性或字段时,都不能与其他成员一起使用

  • 这个表示法是一致的,您不必思考,只需要始终使用“ this”来指代任何成员

更新:如前所述,以下内容不是优势

保养

  • 下划线表示法要求您_在重构时保持警惕,例如将字段转换为属性(删除_)或将字段转换为属性(添加_

  • 这个符号没有这个问题

自动补全

当您需要查看实例成员的列表时:

  • 下划线符号没有太大帮助,因为当您键入“ _”时,自动完成弹出窗口会向您显示私有字段和链接程序集中的所有可用类型以及其余实例成员
  • 通过输入“ this”,此符号可为您提供清晰的答案,您所看到的只是成员列表,仅此而已

歧义性

有时,您必须在没有Intellisense的帮助下处理代码。例如,当您进行代码审查或在线浏览源代码时。

  • 下划线符号不明确:当您看到Something.SomethingElse时,您无法分辨Something是一个类,而SomethingElse是其静态属性...还是Something是当前实例属性,该属性具有自己的SomethingElse属性

  • 这个表示法很明确:当您看到Something.SomethingElse时,它只能表示具有静态属性的类,并且当您看到此内容时。Something.SomethingElse您知道Something是成员,而SomethingElse是其属性

扩展方式

如果不使用“ this”,则不能在实例本身上使用扩展方法。

  • 下划线符号要求您不要使用“ this”,但是对于扩展方法,您必须
  • 此表示法使您免于犹豫,您始终使用“ this”(句号)。

Visual Studio支持

  • 下划线符号在Visual Studio中没有内置支持
  • Visual Studio自然支持此符号:

    1. “这个。” 资格优先使用非静态方法中使用的所有非静态字段this.作为C#的开头

官方建议

有很多官方准则明确指出“请勿使用下划线”,尤其是在C#中


22
这是一个了不起的答案。感谢您抽出宝贵的时间来汇编所有这些信息。
Tigran 2014年

5
并非来自C ++,因为在C ++中,保留的标识符以下划线开头,以表示语言和标准库的用法。
罗布G

7
为什么要区分性能关键的,多线程的,系统级的代码和其他代码?_camelCase如果我的代码是性能关键/系统级代码,该如何使用对我有帮助?
BornToCode

6
使用下划线与编写性能关键的多线程或系统级代码无关。重要的是一致性,CoreFX团队只是一个就特定约定达成一致的团队。这是一个很好的答案,但有一个很好的分析比较命名约定的支持,但是我相信添加的部分说“下划线更好,因为CoreFX团队这样说”确实降低了其质量。
Şafak古尔

5
我的问题是我了解逻辑推理。 en.wikipedia.org/wiki/Inference 但是,嘿,我知道它并不适合所有人。
user603563'3

67

取自Microsoft StyleCop帮助文件:

类型名称: FieldNamesMustNotBeginWithUnderscore

CheckId: SA1309

原因: C#中的字段名称以下划线开头。

规则说明:

当字段名称以下划线开头时,就会违反此规则。

默认情况下,StyleCop禁止使用下划线,m_等标记本地类字段,而使用“ this”。字首。使用“ this”的优势。它可以同等地应用于所有元素类型,包括方法,属性等,而不仅仅是字段,这使得对类成员的所有调用都可以立即识别,无论使用哪种编辑器查看代码。另一个优点是,它可以在实例成员和静态成员之间建立快速,可识别的区分,而不会添加前缀。

如果字段或变量名称旨在与Win32或COM关联的项的名称匹配,因此需要以下划线开头,请将字段或变量放在特殊的NativeMethods类中。NativeMethods类是任何包含以NativeMethods结尾的名称的类,旨在用作Win32或COM包装程序的占位符。如果将该项放置在NativeMethods类中,则StyleCop将忽略此冲突。

另一种不同的规则说明表明,除上述内容外,首选做法是用小写字母开头私有字段,并用大写字母开头公共字段。

编辑:作为后续,StyleCop的项目页面位于此处:https : //github.com/DotNetAnalyzers/StyleCopAnalyzers。通读帮助文件可以深入了解为什么他们建议各种样式规则。


7
这主要是一种“最佳做法”。如规则所述,以“ this”为前缀可以应用于任何非静态成员,而由于语言语法规则,以其他任何形式开头的前缀可能都不适用。“ this”关键字使预期的目标变得很清楚。
Scott Dorman

5
与人为解决问题的方法相比,我也更喜欢该语言针对问题的预期解决方案(“ this”)。
galaktor 2011年

10
在同一软件中还有一条规则,规定您不应只有两个大小写不同的字段。那么,如何处理由公共属性包装的受保护变量呢?
莉莉丝河

5
我唯一的“无下划线”问题是,当针对(web)表单等进行编程时,仅使用“ this”根本无法帮助我过滤掉我定义的那些私有字段,而只是给了我该对象附带的八百万其他属性的巨型列表。

14
StyleCop似乎在说,如果我this在引用任何类成员时始终使用,我可以通过搜索查找所有对所有类成员的调用this。我对此不敢苟同,但也没有想到我需要这样做的时候。我想做的最后一件事是在代码中添加乏味,然后用this几乎是匈牙利语)乱扔我的代码,几乎没有实际收获。事实是,如果我正在看一行代码,则任何以大写字母或下划线开头的都是类成员,任何小写的都是本地的。
devuxer 2012年

27

由于我们在谈论私有字段,因此它不会影响您的班级用户。

但我建议在下划线处使用下划线,因为它可以使代码更易于理解,例如:

private int foo;
public void SetFoo(int foo)
{
  // you have to prefix the private field with "this."
  this.foo = foo;

  // imagine there's lots of code here,
  // so you can't see the method signature



  // when reading the following code, you can't be sure what foo is
  // is it a private field, or a method-argument (or a local variable)??
  if (foo == x)
  {
    ..
  }
}

在我们的团队中,我们始终对私有字段使用下划线前缀。因此,在阅读一些代码时,我可以很容易地识别出私有字段,并把它们与本地变量和参数区分开。从某种意义上说,下划线可以看作“ this”的简写形式。


14
好吧,无论我要访问的是字段,属性还是方法,我总是以“ this”作为前缀。
TheCodeJunkie

9
对我而言,下划线是“ this”的简写形式。
M4N

2
在R#中,建议不要调用参数foo。为什么不将其称为“值”,因为您知道它将用于Set Foo?
thinkbeforecoding

17
@Martin:下划线是“ this”的简写形式的问题在于,当“ this”可以使用时,下划线不一定适用于所有班级成员。我认为使用“ this”关键字可以使代码的读取更加轻松/整洁。在您的示例中,if(foo == x)将始终引用参数foo。
Scott Dorman

3
@TheCodeJunkie:在您的代码库中,有很多多余的字符。
Ed S.

15

从那以后,在具有非常具体且毫无意义的样式规则的环境中工作之后,我继续创建自己的样式。这是我经常来回翻转的一种类型。我终于决定私有字段将始终为_field,局部变量将永远不具有_并将为小写,控件的变量名将宽松地采用匈牙利符号,并且参数通常为camelCase。

我讨厌这个this.关键字,它只会增加太多代码噪音。我爱Resharper移除多余的内容。关键词。

6年更新: 我正在分析内部结构Dictionary<TKey,T>的并发访问的特定用法,并将私有字段误读为局部变量。专用字段绝对不应与局部变量使用相同的命名约定。如果有下划线,那将是显而易见的。


18
this关键字是保证参考当前对象。下划线是您无法理解的。无需厌恶this
杰森S

15
为什么要发明“标准”。'这个。' 告诉您该对象是实例变量“类”。告诉你这是一个类变量。其他所有内容都是堆栈变量。下划线与匈牙利注释法现在分解的那些坏主意相同。
Quarkly 2013年

4
@ DRAirey1太容易错过了这个。当您需要它时,最终会用状态做一些奇怪的事情。
克里斯·马里西克

3
@ChrisMarisic当然欢迎您对的用法提出意见_,但是当显然不是它时,请勿将其视为已建立的标准。
暗恋

3
我因“我继续创造自己的风格”而迷失了你。
rory.ap

12

我喜欢下划线,因为这样我可以将小写名称用作方法参数,如下所示:

public class Person
{
    string _firstName;

    public MyClass(string firstName)
    {
        _firstName = firstName;
    }

    public string FirstName
    {
        get { return _firstName; }
    }
}

39
公共字符串FirstName {get; 私人套装;}
杰森

3
您仍然可以通过使用this关键字将小写字母用作方法参数。在进行中且一直存在争议的“是否强调” public MyClass(string firstName){ this.firstName = firstName; }
中将其设为静音

5
这就是未来,只是现在public string FirstName { get; },二传手仍可在构造函数中使用
Chris Marisic

在这个例子中。this仅在构造函数中是必需的。无需在其他任何地方使用它。因此firstName,字段名称非常有效。
Thomas Eyde

9

我仍然非常喜欢在私有字段前面使用下划线,这是因为马丁提到的原因,也是因为私有字段将在IntelliSense中排序在一起。尽管匈牙利前缀符号通常很邪恶。

但是,最近我发现,对于私有成员使用下划线前缀是不受欢迎的,即使我不太清楚为什么也是如此。也许别人知道吗?仅仅是前缀原则吗?还是在泛型类型的名称处理中涉及到某些问题,这些问题会在编译的程序集中使它们下划线?


4
对我来说,_在快速扫描代码时会把_单词弄得一团糟,它变得不像阅读_和_more _一样,不得不停在_每个_上以确认它,并且_意识到它不是_sort的控制字符。它实际上通过将字段名称中的第一个有用字符推到右侧一列来破坏缩进。我通常不喜欢C ++,因为大多数C ++程序员都倾向于编写令人难以置信的简洁和慢速读取的符号/类似机器的代码,而我只是更喜欢C#代码中没有这样的代码:)
Oskar Duveborn 2013年

22
对我来说,这个。快速遍历代码遍历时,会使this.words变得杂乱无章,这变得不像阅读this.this.this.more.this.like,就像必须停下来并且this.every this。确认它并实现它是this.not而不是某些this.sort的控制字符。我宁愿发现偶然的_fieldFoo或而_fieldBar不是使我的使用混乱this.fieldFoo或混乱this.fieldBar。我发现该this.前缀比领先的下划线要难受得多。
AggieEric

我在想,这种经验上的差异可能源于老式文件系统或文件传输协议,其中不允许使用空格,这使一些用户将下划线视为空格,从而不会分散他们的阅读兴趣。另一方面,我的文件名存在问题,因为我从一开始就一直在自己的文件名中使用空格...
Oskar Duveborn 2014年

1
@AggieEric在那儿砸了钉子。只是读他的句子给我带来了头痛!在这件事上,我试图坚持多年的MS推荐,而且我this到处都读不到蓝色的小字,这让我感到厌倦,于是我做出了一个呆板的决定。现在,我虔诚地this仅将其用于属性引用,或者当我需要明确区分this和时base。我猜每个人都自己:-)
Riegardt Steyn

1
我认为这是因为,最终,任何带有标点符号的内容都会损害可读性。它似乎并没有打扰每个人,但对我来说,阅读任何以标点符号开头的内容都是非常不自然的。代码越像英语,我越容易阅读。借助现代的IDE,很容易分辨本地人和私人成员之间的区别,因为它们很可能是不同的颜色。
Tim Long

5

是否建议使用样式警察,深入研究.NET Framework会发现很多“ _”用于成员变量。无论Style Cop的创建者推荐什么,这都不是大多数MS员工使用的东西。:)所以我会坚持下划线。因为我个人使用下划线然后使用this犯了很多错误(例如:使用varName = varName而不是this.varName = varName,它确实卡在了我体内)


3
.NET核心样式指南也建议使用下划线:github.com/dotnet/corefx/wiki/Coding-style
landoncz

3

我认为,从总体上讲,类级别的字段在语言设计中是一个错误。如果C#的属性具有自己的本地范围,我将更喜欢它:

public int Foo
{
   private int foo;
   get
   {
      return foo;
   }
   set
   {
      foo = value;
   }
}

这样就可以完全停止使用字段。

我唯一一次在私有字段下划线加上前缀是在属性需要单独的后备字段时。这也是我唯一一次使用私有字段。(并且由于我从不使用受保护的,内部的或公共的字段,所以这是我唯一使用字段期间的时间。)就我而言,如果变量需要具有类作用域,则它是该类的属性。


C#帮派似乎同意您与新的私有int foo {get; set;}语法糖。
Dana

行,可以; 没有这些,我在这里描述的内容是完全不可行的。
罗伯特·罗斯尼

您要描述的是“自动实现的属性”。不幸的是,在Visual Basic.NET中,它实际上在幕后使用了“隐藏的” _prefix变量,即,如果您具有自动实现的属性“ Public Property Foo As Integer”,那么就不能具有成员变量声明“ Private _foo as整数”

不,我没有描述自动实现的属性,至少在我的示例中没有。我描述的是C#或VB中不存在的作用域范围。真不幸的是,VB选择了这样一种琐碎的方法来修饰后备字段的名称。C#非常丑陋,您永远不会偶然创建一个具有相同名称的变量。
罗伯特·罗斯尼

3

专用字段的_fieldName表示法很容易被破坏。使用“ this”。表示法是不可能打破的。您将如何打破_表示法?观察:

private void MyMethod()
{
  int _myInt = 1; 
  return; 
}

到了那里,我只是违反了您的命名约定,但是可以编译。我希望有一个命名约定,即a)不匈牙利和b)明确。我赞成取消匈牙利命名,这在某种意义上是合格的。您无需访问变量名称前面的对象类型,而拥有其访问级别。

将此与Ruby进行对比,在Ruby中,变量@my_number的名称将名称绑定到范围中,并且牢不可破。

编辑:这个答案是否定的。我不在乎,它保持不变。


11
说开发人员可能不遵循命名约定并不是什么有效的批评。
罗伯特·罗斯尼 Robert Rossney)2009年

8
哇,您对“容易打破”和我的定义完全相反。您的意思是“容易故意破坏”,而其他大多数人可能是“容易意外破坏”。我将它留给读者作为练习,以找出哪种代码与编写可读代码更相关……
Konrad Rudolph

6
@Konrad:当您说“作为对读者的练习”时,您听起来很自负。这不是一本数学教科书。
jcollum

3
现在,负面影响要小一些:)虽然我们可能与当前潮流相抵触,但我也不喜欢下划线约定。在我看来,这与匈牙利表示法没什么不同,老实说,它使我的眼睛流血(容易阅读)。我们用C#淘汰了匈牙利符号,现在该是不信任您的IDE的最后痕迹了。
Tim Long

1
我听说MS实际上说在其C#样式指南中不要使用下划线。blogs.msdn.microsoft.com/brada/2005/01/26/…–第2.6节–看来Brad Abrams至少同意我们的观点!
jcollum

1

如果要使程序集符合CLS,则可以在assemblyinfo文件中使用CLSCompliant属性。然后,当您的代码包含不符合cls的内容时,编译器将发出抱怨。

然后,当您具有2个仅大小写不同的属性时,编译器将发出错误。另一方面,当您在同一类别中拥有私有领域和公共财产时,就不会有问题。

(但是,我也总是在私有成员的前面加上下划线。这也有助于我在读取代码时明确指出某个变量是成员字段)。


0

我喜欢在私有字段前面使用下划线,原因有二。已经提到过一个,这些字段在代码和Intellisense中从其关联属性中脱颖而出。第二个原因是,无论我是在VB还是C#中进行编码,我都可以使用相同的命名约定。


1
哇,那明智吗?下划线不是在VB中表示“下一行继续”吗?
JBR威尔金森

1
仅在下划线后跟空格时。
罗布·温莎

首字母是小写或大写对我来说很好:)
ManoDestra '16

0

没有任何暗示。编译代码时,对编译器而言重要的是字段/属性的名称空间和可见性。命名标识符时,下划线与任何其他字符一样重要。真正的诀窍是使用您和您周围的人会理解的约定。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.