'var'和null合并运算符'??'应该走多远 在不影响可读性的情况下进行娱乐?


23

我知道问题的标题是非常主观的,但是??我的同龄人遇到了使用运算符的问题,而与此同时,我对申请var新的即将出现的代码并不满意/不满意。

使用??operator 给出的参数是,它占用了代码的可读性。

我的问题是,开始使用时会发生同样的事情var吗?


49
如果“开发人员”??在解释后无法理解null合并运算符,则不应在生产代码附近使用它们。
CaffGeek 2011年

12
我建议我们将运算符从??更改。到IfNullThen。?可以是IfSoChoose ,:是ElseChoose。+是添加。-是减法,除非一元,否则是负数。-在DecrementBeforeUsing和DecrementAfterUsing之间拆分。在C ++中,您可以使用宏进行此操作。
Lee Louviere

7
@Xaade:讽刺的是吗?... 对?……上帝要讽刺(我是无神论者)。
史蒂文·杰里斯

10
@StevenJeuris也许是讽刺,但这并不具有讽刺意味
柯克·布罗德赫斯特

1
@KirkBroadhurst:我的立场是正确的,一直使这两个混淆。
史蒂文·杰里斯

Answers:


53

空合并运算符(??)

就个人而言,我认为使用此运算符没有任何不利影响。考虑以下三个代码示例,从“简单”到“复杂”新运算符。

没有魔术:

bool isNameSet = false;
string name;
if ( isNameSet )
{
    Console.WriteLine( name );
}
else
{
    Console.WriteLine( "No name set." );
}

三元运算符:

bool isNameSet = false;
string name;
Console.WriteLine( isNameSet ? name : "No name set." );

空合并:

string name = null;
Console.WriteLine( name ?? "No name set." );

这些运算符之所以被发明是因为它们代表了非常普通的编程操作。因为您不习惯它们而不想使用它们只是固执。语言在发展,功能在发展,学会使用它们!

var关键字

我对var关键字有不同的看法。变量的类型通常会提供有关代码的更多信息。我发现使用var关键字隐藏类型有时会使代码的可读性降低。在不使用自动完成功能或将标识符悬停在标识符上以查看其实际含义的情况下,您所知不多。在我看来,这导致代码的读取/写入速度较慢。

当我发现类型没有提供太多额外信息时,我确实使用了关键字。

  • 我主要在foreach循环中,这是我从Resharper那里学到的,因为它是那里的设置。在大多数情况下,您知道要遍历的集合类型,因此您知道期望该集合中的项。
  • Linq查询。linq查询的结果通常是非常复杂的泛型类型。显示此类型弊大于利。
  • 长类型名称,只需使用其构造函数进行初始化即可。通过查看构造函数,您已经可以知道类型是什么。

作为最后一条语句的示例:

ThisIsSomeSpecializedTypeRightHere duplication =
    new ThisIsSomeSpecializedTypeRightHere();
var justAsReadable =
    new ThisIsSomeSpecializedTypeRightHere();  // Less duplication.

// But I still prefer the following ...
int number = 9;
SomeCreatedType foo = Factory.CreateSomeType();

24
最后一个示例正是var关键字可以胜任的时间。想象一下,整个代码中到处都是乱码。Factory.CreateSomeType返回IEnumerable<SomeType>。有一天,无论出于什么原因,它都会变回去SomeType[]。如果您使用过var,那只是重新编译。
pdr

1
弄错了那个例子,然后去寻找食物。脾气暴躁!一个更好的例子是使用您的。如果Factory.CreateSomeType()更改返回值ISomeType怎么办?
pdr

4
@pdr:这很可能意味着界面也已更改,并且行为也需要调整/添加。如果是简单的重命名,那么您当然可以自动重命名。如果“合同”发生了变化,我宁愿看到我的代码被破坏,所以我可以查看是否需要调整某些内容。
Steven Jeuris 2011年

2
我认为,如果返回具体类型成为返回接口的可能性更大,那么它仅允许具有相同接口(与Factory模式一致)的其他具体类型。但是,如果合同确实发生更改,则您的代码将被破坏-尽管您可能会发现它只在某些情况下才有意义,而不是在所有情况下都被破坏。
pdr

1
@Tom Hawtin,我们都知道null完全避免不可避免。此外,我寻找的替代品null越多,null有时我意识到使用的是最干净的解决方案。我给定的例子并不是那么糟糕,恕我直言,我发现它是可空类型的适当用法。
Steven Jeuris 2011年

16

var允许使用更少的冗长代码,从而增加了可读性。我认为,可读性不应该用看到的细节来衡量,而应该乍一看就隐藏了多少细节。除了Linq示例,var还允许在源代码级别进行鸭子输入,如下例所示:

...
foreach (var message in messages) {
  var label = Factory.CreateLabel();
  label.Text = message;
  Controls.Add(label);
}
...

谁在乎标签的类型是什么,只要它提供Text属性?


有人试图了解这是Winforms标签还是WPF标签。
Steven Jeuris 2011年

14
@Steven Jeuris:通常是已知的上下文信息。否则,您将以错误的方式处理代码。
Codism 2011年

有人想知道它是默认WPF标签还是某些自定义标签?:)
史蒂芬·杰里斯

14
1.只要是带有Text属性的标签,该人是否应该真正在乎?2.如果这是他们确实有充分理由理会的罕见情况之一,请询问Intellisense。3.如果他们在没有Intellisense的IDE中编辑代码,则可能带来的麻烦要比'var'
大得多

4
缺乏抽象感的人。
吉姆·巴尔特

16

我对??运算符没有任何严肃的评论,因为我从未在这样的运算符上大量使用过一种语言。关于var,人们使用Ruby,Python,Perl和PHP这样的语言进行编程,这些语言始终具有完全隐式的输入。这些语言的本地人意识到,变量的形式类型通常是无关紧要的。您对变量可以什么更感兴趣,即它的结构/鸭子接口。

同样,我主要使用D进行编程。D是静态类型的,但具有auto关键字,它等效于var。除非您看到需要向阅读器或(通过隐式转换)编译器强调某种类型的特殊需求,否则在任何地方都使用它被认为是惯用的。除了偶尔用作函数返回类型(在D中允许)外,我从未发现它会妨碍可读性,因为在我编程时,我主要是考虑结构/鸭子接口,而不是形式/标称类型。

此外,恕我直言var,尽可能地使用DRY就是一个很好的例子。事物的类型应在一个且只能在一个地方指定,然后在需要传播时自动传播。如果您使用var并且变量的形式类型需要在某个时候进行更改,则只要程序仍然是类型正确的,必要的更改将自动传播到编译器需要的所有地方,而程序员不必手动更改每个实例。这是一件好事(TM)。


13

我认为这最终是团队的问题。如果我的团队中的其他任何人都看不懂它,那么我将不会使用它,尽管我可能会尝试几次用示例来说服他们,或者指出类似的缩写(例如+ =),以使它们更易读。

但是,如果独自工作,我会发现?? 和var无限制地可读。甚至

var a = b ?? c ?? d ?? e ?? "";

对我来说很明确。

dynamic当然,三元运算符是另一回事。


4
我会在这里使用`String.Empty'。
工作

1
@Job,老实说,我也一样。我打算在该字符串中放一些东西,然后什么也没想到:)
pdr

4
var a = b ?? c ?? d ?? e ?? String.Empty ?? "";
Lee Louviere

2
@Xaade您永远无法确定。但实际上,使用String.Empty或“”是个人喜好。我使用“”是因为它更短……
Carra

12
@Xaade-如果String.Empty返回null,我们将陷入很多破损代码的泥潭。
Jesse C. Slicer

10

使用??给出的参数 运算符是,它消除了代码的可读性。

简短地思考一下,此评论告诉我进行评论的人,对它的理解不尽如人意。在某些情况下,这很可能是正确的,但是总的来说,我不反对C#团队显然出于“可读性”而认为足够重要的东西。我把它放在if(boolean_object)vs 的同一类别中 if(boolean_object == true)。有人认为第二个代码更具可读性,但实际上,它只是添加了一些额外的代码供他人阅读/输入,在某些情况下可能会更加令人困惑(请思考if(boolean_object != false)

我的问题是,当您开始使用var时会发生同样的事情吗?

C#团队允许您不定义某些东西,而这些东西您将要知道。除非我绝对不需要定义变量将是什么(返回对象的类型为x绝对重要,或者它实际上是不可读的),否则我会使用varvar x = "MY_STRING";我知道这是一个字符串。实际上,只要它满足我的要求,我就不会在乎它是字符串。定义变量类型是为了我的利益,而不是编译器的利益。如果出现问题,如果变量类型错误,编译器会告诉我何时运行。


0

var在我看来,该关键字最好在最初引入的情况下使用-LINQ查询。在这些查询中,返回结果的类型通常具有一些复杂的名称,很难事先确定,并且不利于读者理解代码的作用。

但是,这样做var text = "Some text " + variableName + "some more text."只是懒惰。

编辑:@Jorg您跳了一个有目的的简单答案,但没有添加任何讨论。好的,如何做一个更好的例子:var items = doc.DocumentElement.FirstChild.ChildNodes;如果您能从中找出类型,我给您一个cookie。


18
如果您不知道这"Some text "是一个string,那么您要担心的问题比var代码中s 的数目大得多。
约尔格W¯¯米塔格

3
问题不是var; 问题是糟糕的变量名称“ items”。如果您使用好的变量名,那么没什么问题var
Kyralessa

3
我猜(没有看)这些项目是XML节点的集合,我希望它具有XML节点集合的所有属性和方法,而这正是我需要知道的全部。
KutuluMike 2011年

如果您需要知道var代表什么类型并且无法通过查看立即得知,只需将鼠标悬停在它上面。并不需要花很多时间去做。
scrwtp 2011年

1
“只是懒惰”-这不是反对它的理由。实际上,它根本不是智能的。
吉姆·巴尔特

0

我在使用var时遇到一个基本问题。

在此示例中,所有内容都是并行的,但是问题实际上是共享库或项目的大型解决方案。

考虑一下:

public MyFirstObject GetMeAnObject() {
    return new MyFirstObject();
}

public void MainProgram() {
    var theObject = GetMeAnObject();
    theObject.PerformOperation();
}

如果其他人更改了GetMeAnObject以适应他们的需求会怎样?

public MySecondObject GetMeAnObject() {
    return new MySecondObject();
}

MainProgram方法在.PerformOperation()上将有一个大的红色错误。发生了什么?PerformOperation之前运行得很好。我们看一下对象上的方法,它消失得无影无踪。上次在那里,我们需要那种方法。您可能需要花费很长时间来追尾,并试图找出原因,如果MyFirstObject有一个名为PerformOperation的方法,则现在看不到它。每个人都“知道” GetMeAnObject返回了MyFirstObject,因此毫无意义地进行检查。

如果您已显式键入theObject,则在调用GetMeAnObject的行上将出现Invalid Cast错误,并且很明显,GetMeAnObject返回的类型不是您期望的类型。

简而言之,显式声明意味着您知道错误的含义。无效的强制转换意味着您期望一种类型,而返回了另一种类型。无法识别的成员表示该成员未被识别。


10
一位同事对代码进行了重大更改,测试未涵盖该代码,您认为问题出在var哪里?不能指望该语言能够防止这种行为-如果他们直接修改MyFirstObject会怎样?它仍然会坏掉,但是没有语法可以使您摆脱困境。我var甚至认为这是一个优势:如果不是现在返回IMyFirstObject而不是返回MySecondObject,该怎么办?
Phoshi 2012年

2
“每个人都“知道” GetMeAnObject返回了MyFirstObject,因此毫无意义地进行检查。” 我实际上无法想到编程中的一种情况,在这种情况下,如果要调试,我实际上将取决于我对GetMeAnObject的记忆。如果我检查PerformOperation是否不存在,那我应该已经看过代码了,不,它适用于另一个类。如果在IDE中该类会弹出该实例,那么我将查看对象的类型。实际上,当编译器告诉我该错误时,它将说“类MySecondObject没有执行PerformOperation操作”。大家怎么知道?
Muhammad Alkarouri
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.