「var」およびヌル合体演算子「??」読みやすさを妨げることなく楽しまれる?


23

私は質問のタイトルが非常に主観的であることを知っていますが??、私は同僚によるオペレーターの使用に直面しましたvar

??演算子を使用するための引数は、コードの可読性を奪います。

私の質問は、使用を開始したときに同じことは起こりませんvarか?


49
「開発者」??説明後にヌル合体演算子を理解できない場合、実動コードの近くでそれらを許可すべきではありません。
CaffGeek

12
演算子を??から変更することをお勧めします。IfNullThenに。?IfSoChoose 、:はElseChooseです。+は追加です。-減算です。単項でない限り、負です。-DecrementBeforeUsingとDecrementAfterUsingに分割されます。C ++では、マクロを使用してこれを行うことができます。
リールーヴィエール

7
@Xaade:それは皮肉じゃないですか?... 右?...神はそれを皮肉にします(そして私は無神論者です)。
スティーブンジュリス

10
それはあるかもしれない@StevenJeuris 皮肉、しかし、そうではありません皮肉
カークブロードハースト

1
@KirkBroadhurst:私は修正されており、常にこれら2つを混乱させてきました。
スティーブンジュリス

回答:


53

ヌル合体演算子(??)

個人的には、この演算子を使用することの欠点はありません。「簡単」から「複雑な」新しい演算子まで、次の3つのコードサンプルを検討してください。

魔法なし:

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>。ある日、なんらかの理由で、returnに変わりますSomeType[]。varを使用した場合、それは単なる再コンパイルです。
pdr

1
その例を間違った方法で入手してから、食べ物を探しに行きました。ナンプティ!より良い例は、あなたのものを使用することです。Factory.CreateSomeType()を返すように変更するとどうなりますISomeTypeか?
pdr

4
@pdr:それはおそらくインターフェイスも変更されたことを意味し、動作も調整/追加する必要があります。単純な名前変更の場合、もちろん名前の自動変更が可能です。「契約」が変更された場合、コードが壊れているのを見るので、何かを調整する必要があるかどうかを確認できます。
スティーブンジュリス

2
具象型を返すことがインターフェイスを返すようになった場合、同じインターフェースを持つ他の具象型を許可するだけである可能性がはるかに高いと思います(Factoryパターンと一致)。しかし、契約が変更された場合、コードは破損します。ただし、破損するのは、それがどこよりも重要である少数の場合のみです。
pdr

1
@Tom Hawtin、私たちは皆、null完全に避けることは避けられないことを知っています。さらに、の代替物を探すほどnull、使用するnullことが最もクリーンなソリューションであることに気づきます。私の与えられた例はそれほど悪い私見ではありません、そして私はそれがnullable型の適切な使用法であるとわかります。
スティーブンジュリス

16

varを使用すると、冗長なコードが少なくなり、読みやすくなります。私の意見では、読みやすさは表示される詳細の数ではなく、一目で隠されている詳細の数によって測定されるべきではありません。Linqの例に加えて、varを使用すると、次の例のように、ソースコードレベルでのカモの入力が可能になります。

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

Textプロパティを提供する限り、誰がラベルのタイプを気にしますか?


これが例えばwinformsラベルかWPFラベルかを理解しようとしている人。
スティーブンジュリス

14
@Steven Jeuris:それは通常、既知のコンテキスト情報です。そうでない場合は、間違った方法でコードに近づいています。
コーディズム

それがデフォルトのWPFラベルであるかカスタムラベルであるかを知りたい人はいますか?:)
スティーブンジュリス

14
1. Textプロパティを持つラベルである限り、その人は本当に気にする必要がありますか?2.これが、彼らが本当に気にする正当な理由があるというまれなケースの1つであるならば、Intellisenseに尋ねてください。3.
IntelliSenseを

4
抽象感が乏しい人。
ジムBalter

16

私はそのような??演算子で言語を多用したことがないので、演算子に関する深刻なコメントはありません。に関してはvar、人々はRuby、Python、Perl、PHPなど、常に完全に暗黙的な型付けを行う言語でプログラムを作成します。これらの言語のネイティブは、変数の正式な型が通常は無関係なノイズであることを認識しています。あなたは、変数ができること、すなわちその構造/ダックインターフェースにもっと興味があります。

同様に、私はほとんどDでプログラムします。Dは静的に型付けされていますが、autoキーワードがあり、これはと同等varです。読者または(暗黙の変換を介して)コンパイラーに対して何かのタイプを強調する特定の必要性が見られない限り、どこでも使用するのが慣用的であると考えられます。関数の戻り値の型として使用される場合を除き(これはDで許可されています)、読みやすさを妨げることは一度もありません。なぜなら、プログラムするときは、主に正式/主格型ではなく、構造/ダックインターフェイスの観点から考えるからです。

さらに、var可能な限りあらゆる場所で使用するIMHO は、DRYの良い例です。何かのタイプは1か所でのみ指定し、それが伝達される必要があるときはいつでも自動的に伝達される必要があります。使用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 ?? "";
リールーヴィエール

2
@Xaadeあなたは十分に確信することはできません。しかし、実際には、String.Emptyまたは ""を使用することが個人的な好みです。それは...短いですので、私は「」を使用
CARRA

12
@Xaade- String.Empty戻ってきたとしてもnull、私たちは多くの壊れたコードの1つの地獄にいます。
ジェシーC.スライサー

10

??を使用するために指定された引数 演算子は、コードの可読性を奪います。

簡単に考えてみると、このコメントはコメントを行っている人に私に伝えるものであり、理解すべきではありません。特定の状況ではおそらくそうなりますが、全体として、C#チームが「読みやすさ」のために追加するのに十分に重要であると明らかに考えていたものを割引しません。これを同じカテゴリのif(boolean_object)vs に入れました if(boolean_object == true)。2番目の方が読みやすいと主張する人もいますが、実際には誰かが読み取り/入力するためのコードを追加するだけであり、状況によってはもっと混乱する可能性があります(考えてみてくださいif(boolean_object != false)

私の質問は、varの使用を開始すると同じことは起こりませんか?

C#チームは、あなたがそれがどうなるかを知っている何かを定義しないことを許可しました。変数がどうなるかを絶対に定義する必要がない限り(返されるオブジェクトがx型であることが絶対に重要であるか、実際に読み取り不可能であるかのいずれか)、を使用しますvarvar x = "MY_STRING";私はそれが文字列であることを知っています。実際、必要なことを実行する限り、文字列であることはあまり気にしません。変数の型を定義することは、コンパイラーではなく、私の利益のためです。何かが間違っている場合、コンパイラは、変数の型が間違っていると実行時に通知します。


0

var私の意見では、このキーワードは、それが最初に導入された状況(LINQクエリ)で使用されるのに最適です。これらのクエリでは、返される結果のタイプには、事前に判断するのが難しく、コードが何をするのかを読者が理解するのに役立たない複雑な名前が付けられていることがよくあります。

ただし、やるのvar text = "Some text " + variableName + "some more text."は怠け者です。

編集:@Jorgあなたは意図的に単純化した答えに飛びついたが、議論には何も追加しなかった。OK、これより良い例についてはどうvar items = doc.DocumentElement.FirstChild.ChildNodes;でしょうか。もしあなたがそれからタイプを見つけられるなら、私はあなたにクッキーを与えます。


18
あなたはそれを見つけ出すことができない場合"Some text "string、あなたは数よりも心配することははるかに大きな問題を抱えてvarあなたのコードで秒。
ヨルグWミットタグ

3
問題はありませんvar。問題は、くだらない変数名「items」です。適切な変数名を使用する場合、に問題はありませんvar
キラレッサ

3
アイテムはXMLノードのコレクションであり、XMLノードのコレクションのすべてのプロパティとメソッドを持っていることを期待していますが、実際に知っておく必要があるのはこれだけです。
KutuluMike

varがどのタイプを表しているのかを調べてすぐに判断できない場合は、その上にマウスを置いてください。それを行うために多くを理解することはありません。
scrwtp

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は以前は完全に機能していました。theObjectのメソッドを見ると、トレースなしで消えています。前回はそこにいたので、その方法が必要です。MyFirstObjectにPerformOperationと呼ばれるメソッドがある場合、今は見えないので、長い時間をかけて尾を追いかけて理由を突き止めようとします。GetMeAnObjectがMyFirstObjectを返すことは誰もが「知っている」ので、それを確認する意味はありません。

theObjectを明示的に入力した場合、GetMeAnObjectを呼び出す行で無効なキャストエラーが発生し、GetMeAnObjectが予期しない型を返していることは明白です。

つまり、明示的な宣言は、エラーの意味を知っていることを意味します。無効なキャストは、1つのタイプを予期し、別のタイプが返されたことを意味します。認識されないメンバーは、そのメンバーが認識されなかったことを意味します。


10
同僚がテストでカバーされていないコードに重大な変更を加えましたが、問題はvar?この言語は、そのような動作から保護することは期待できません。MyFirstObjectを直接変更した場合はどうでしょうか。それはまだ壊れていましたが、構文はそれからあなたを救うことができませんでした。私はこれをの強さとvarさえ考えています:MySecondObjectを返す代わりにIMyFirstObjectを返すとしたらどうでしょうか?
-Phoshi

2
「GetMeAnObjectがMyFirstObjectを返すことは誰もが「知っている」ので、それをチェックする意味はありません。」デバッグしている場合、GetMeAnObjectの記憶に実際に依存するプログラミングのシナリオを実際に考えることはできません。PerformOperationが存在しないことを確認した場合、コードが表示され、別のクラス用ではありません。IDEでクラスがインスタンスをポップアップする場合、オブジェクトのタイプを確認します。実際、コンパイラーがエラーを通知すると、「クラスMySecondObjectには操作PerformOperationがありません」と表示されます。誰もが知っていることはどうですか?
ムハンマドアルカウリ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.