web-dev-qa-db-ja.com

なぜvarは悪いことなのでしょうか?

先日同僚とチャットしていて、彼らのコーディング標準ではC#でvarキーワードを使用することが明示的に禁止されていると聞きました。彼らはそれがなぜそうなのか見当がつかず、私は常に暗黙の宣言がコーディング時に信じられないほど役立つことを発見しました。変数がどのタイプであるかを見つけるのに問題はありませんでした(VSで変数にカーソルを合わせるだけで、その方法でタイプを取得できます)。

C#でvarキーワードを使用するのが悪い考えである理由を誰かが知っていますか?

48
Spoike

2008年11月に発表された 。Net Framework Design Guidelines (すばらしい本)の執筆者は、タイプが明白で明確な場合はvarの使用を検討することを推奨しています。

一方、Anton Gogolevが指摘したように、varを使用するとコードの読み取り時にあいまいさが生じる場合は、使用しない方がよいでしょう。

本(付録A)では、実際に次の例を示しています。

var names = new List<string>(); // good usage of var

string source = GetSource();
var tokens = source.Split(' '); // ok; most developers know String.Split

var id = GetId(); // Probably not good; it's not clear what the type of id is

読みやすさが低開発者の気まぐれにさらされないようにするために、組織はあなたがvarに値しないと判断し、それを禁止した可能性があります。
それは残念ですが、素敵な道具を自由に使えるが、鍵のかかったガラスのキャビネットに保管しているようなものです。

ほとんどの場合、単純な型にvarを使用すると読みやすさが向上し、varを使用してもパフォーマンスが低下しないことを忘れてはなりません。

63
Renaud Bompuis
var q = GetQValue();

確かに悪いことです。しかしながら、

var persistenceManager = ServiceLocator.Resolve<IPersistenceManager>();

私にはまったく問題ありません。

要点は次のとおりです。説明的な識別子名を使用すれば、うまくいくでしょう。

補足として:varキーワードの使用が許可されていない場合、匿名型をどのように処理するのでしょうか。それとも彼らはそれらを完全に使用しませんか?

33
Anton Gogolev

ほとんどの場合、賢明に使用する場合(つまり、型と値が同じである単純な型初期化子)、それで問題ありません。

変更によって問題が発生したことが不明な場合があります。主に、初期化された型と(元の)変数型が同じでない場合です。

  • 変数は元々基本クラスでした
  • 変数は元々インターフェースでした
  • 変数は元々、暗黙の変換演算子を持つ別の型でした

このような場合、次のようなタイプの解決で問題が発生する可能性があります。

  • 2つの競合するタイプに対して異なるオーバーロードを持つメソッド
  • 2つの競合するタイプに対して異なる方法で定義された拡張メソッド
  • タイプの1つで再宣言(非表示)されたメンバー
  • ジェネリック型推論の動作は異なります
  • オペレーターの解決は異なる働きをします

このような場合、コードの意味を変更して、別のことを実行します。これは悪いことです。

例:

暗黙の変換:

static void Main() {
    long x = 17;
    Foo(x);
    var y = 17;
    Foo(y); // boom
}
static void Foo(long value)
{ Console.WriteLine(value); }
static void Foo(int value) {
throw new NotImplementedException(); }

メソッドの非表示:

static void Main() {
    Foo x = new Bar();
    x.Go();
    var y = new Bar();
    y.Go(); // boom
}
class Foo {
    public void Go() { Console.WriteLine("Hi"); }
}
class Bar : Foo {
    public new void Go() { throw new NotImplementedException(); }
}

17
Marc Gravell

確かにこれは間違いです。これは、VBの変数とはまったく異なり、実際には強く型付けされていることに気付いていない人がいるためです。

すべての企業コーディング標準が意味をなすわけではありません。私はかつて、すべてのクラス名の前に会社名を付けたいという会社で働いていました。会社が名前を変えたとき、大規模な手直しがありました。

16
NeedHack

まず、原則として、コーディング標準についてチームが話し合い、合意し、その背後にある理由を書き留めて、誰もがなぜそこにあるのかを理解できるようにする必要があります。彼らは一人のマスターからの聖なる真実であってはなりません。

第二に、このルールはおそらく正当化されます。なぜならコードは書き込まれるよりも読み取られる回数が多いvarは書き込みを高速化しますが、読み取りを少し遅くする可能性があります。 2つの選択肢(varの記述と型の記述)はまったく同じ動作をするため、「常に変数を初期化する」のようなコード動作ルールではないことは明らかです。したがって、これは重要なルールではありません。 varを禁止するのではなく、「Prefer ...」を使用します。

8
Daniel Daranas

私は数ヶ月前にこのトピックに関するブログ記事を書きました。私にとっては、可能な限りそれを使用し、型推論を中心にAPIを具体的に設計しています。私が型推論を使用する基本的な理由は

  1. 型安全性を低下させることはありません
  2. 暗黙のキャストを警告することで、コードの型安全性が実際に向上します。 foreachステートメントの最良の例
  3. DRY C#の原則を維持します。これは特に宣言の場合のためです。なぜわざわざ名前を2回言うのですか?
  4. 場合によっては、完全に必要です。匿名タイプの例
  5. 機能を失うことなくタイピングが少なくなります。

http://blogs.msdn.com/jaredpar/archive/2008/09/09/when-to-use-type-in​​ference.aspx

8
JaredPar

varは、最新の「ブレースのレイアウト方法」/ハンガリアン記法/キャメルケースの討論です。正しい答えはありませんが、極端に座っている人がいます。

あなたの友人は、彼らが過激派の1人の下で働いているのは残念です。

5
Garry Shutler

禁止するということは、匿名型の使用を完全に禁止することを意味します(これは、LINQをさらに使用するにつれて非常に便利になります)。

誰かが匿名型を決して使用しない正当な理由を形式化できない限り、これは愚かで単純明快です。

5
ShuggyCoUk

誤用すると読みやすさが損なわれる可能性があります。ただし、完全に禁止すると、同僚が匿名型を使用しないと苦労するため、少し奇妙です。

4
Andrew Hare

これは本当にあなたのコードの読みやすさの問題です。

私の個人的な好みは、匿名型には「var」のみを使用することです(実際、匿名型を使用する場合は、varを使用する必要があります)。これらは主にLINQクエリから取得されます。このような場合、クエリが新しい(暗黙的および匿名の)型に投影されている場合は、varを使用する以外に選択肢はありません。

ただし、C#3.0では、LINQや匿名型以外の任意の場所でvarを使用できます。例:

var myint = 0;
var mystring = "";

は完全に有効であり、myintとmystringは、それらを初期化するために使用される推定値によって強く型付けされます。 (したがって、myintはSystem.Int32であり、mystringはSystem.Stringです)。もちろん、変数を初期化するために使用される値を見ると、暗黙的に入力されるタイプは明らかですが、上記のように記述されていると、コードの可読性がさらに向上すると思います。

int myint = 0;
string mystring = "";

それらの変数がどのタイプであるかが一目ですぐにわかるからです。

このやや紛らわしいシナリオを考えてみましょう。

var aaa = 0;
double bbb = 0;

完全に有効なコード(少し型破りな場合)ですが、上記では、初期化値がintのように見えても、bbbがdoubleであることはわかっていますが、aaaは間違いなくdoubleではなく、intになります。

3
CraigTP

C#は彼らの言語であるため、Microsoftの意見は適切であると考えるかもしれません。

「ただし、varを使用すると、少なくとも他の開発者がコードを理解しにくくなる可能性があります。そのため、C#のドキュメント通常、varは、必要な場合にのみ使用します。」

MSDN-暗黙的に型指定されたローカル変数(C#プログラミングガイド) 、最後の段落を参照してください。


また、varは、最初の割り当てでのコンパイル時のデータ型テストを削除することにも注意してください。

var x = "mistake";     // error not found by compiler
int x = "mistake";     // error found

ほとんどの変数は1回しか割り当てられないため、varを一貫して使用すると、変数の割り当てに関するほとんどすべてのデータ型テストが削除されます。

これにより、コードが偶発的な変更に対して脆弱になります。マージツールや疲れた開発者によって作られたもの。

3
user1023602

エリック・リペット うまくまとめる

  • 必要な場合はvarを使用してください。匿名タイプを使用している場合。
  • 宣言のタイプが初期化子から明らかな場合、特にオブジェクト作成の場合は、varを使用します。これにより、冗長性が排除されます。
  • コードが変数のセマンティックな「ビジネス目的」を強調し、そのストレージの「機械的な」詳細を軽視している場合は、varの使用を検討してください。
  • コードを正しく理解して維持するために明示的な型を使用する必要がある場合は、明示的な型を使用してください。
  • 「var」を使用するかどうかに関係なく、記述変数名を使用します。変数名は、ストレージの詳細ではなく、変数のセマンティクスを表す必要があります。 「decimalRate」は悪いです。 「interestRate」は良いです。

私自身の意見:intstringbool、さらにはUserなどのタイプでは、読みにくく、少し意味がありません。結局のところ、読みやすさに関するものです(LINQで使用する場合を除く)。したがって、変数が飛び散ると、読みにくくなり、言語設計者が意図したキーワードの目的が損なわれる可能性があります。

2
Chris S

暗黙のタイピングは素晴らしいです、そしてそれを平らにする人々はそれが生産性を損ないそして壊れやすいコードを招くことを禁じます。

これは、タイプセーフでコンパイラーチェックのダックタイピングのようなもので、リファクタリング時に非常に便利です。たとえば、リストを返すメソッドがあり、それをリファクタリングしてIEnumerableを返す場合、varキーワードを使用し、IEnumerableメソッドのみを使用するそのメソッドの呼び出し元はすべて問題ありません。たとえばListなどを明示的に指定した場合は、どこでもIEnumerableに変更する必要があります。

明らかに、暗黙的な型指定の呼び出し元のいずれかがListメソッドを必要とする場合、ビルド時にコンパイルエラーが発生しますが、その場合は、とにかく戻り値の型を変更するべきではなかったでしょう。

2
Mark Rendle

Department of Declaration Redundancy Department (from Jeff's Coding Horror ):

「コードをより簡潔にするときはいつでもどこでも暗黙の変数入力を使用します。コードから冗長性を取り除くものはすべて、言語の切り替えまで、積極的に追求する必要があります。」

私自身、検討する価値があると思いますが、いつ使用するかどうかに関する包括的なガイドラインを作成することはoverkill

2
doekman

Varを使用すると、実際のDataRow型ではなく、基本クラスの型になる場合がありました(Table.Rowsコレクションを介してforeachした場合)。それは私がvarで問題を抱えた唯一の時です。

1
Ries

'var'は明確であることについてです

varキーワードを使用するかどうかについての主な議論は、あなたや他の開発者にとってコードがどれだけ読みやすいかということです。

あなたが物語を書いているかのように、決定的な正解はありません。しかし、これのいくつかの例を平易な英語で見てみましょう。

ジェイクはビルに挨拶した。彼は彼が好きではなかったので、彼は向きを変えて反対方向に行きました。

誰が反対に行きましたか?ジェイクまたはビル?この場合、「Jake」と「Bill」はタイプ名のようなものです。そして、「彼」と「彼」はvarキーワードのようなものです。この場合、より具体的にすることが役立つ場合があります。たとえば、次の方がはるかに明確です。

ジェイクはビルに挨拶した。ジェイクはビルが好きではなかったので、彼は向きを変えて反対方向に行きました。

この場合、より具体的にすることで文がより明確になりました。しかし、それが常に当てはまるとは限りません。場合によっては、具体的であると読みにくくなります。

ビルは本が好きなので、ビルは図書館に行き、ビルはいつも好きだった本を取り出しました。

この場合、「彼」を使用し、場合によっては彼の名前をすべて一緒に省略した方が文章を読みやすくなります。これは、varキーワードを使用するのと同じです。

ビルは本が好きなので、図書館に行っていつも好きな本を取り出しました。

これらのアナロジーは要点をカバーしていますが、全体像を伝えるものではありません。それらの例では、その人を参照する方法は1つしかありませんでした。ビルのように名前を付けるか、「彼」や「彼」のようにもっと一般的な方法で。しかし、私たちは1つのWordでしか作業していません。

コードの場合、タイプと変数名の2つの「単語」があります。

Person p = GetPerson();

ここで問題となるのは、pが何であるかを簡単に判断するのに十分な情報があるかどうかです。このシナリオで人々が何であるかをまだ知っていますか:

var p = GetPerson();

これはどう:

var p = Get();

これはどう:

var person = Get();

またはこれ:

var t = GetPerson();

またはこれ:

var u = Person.Get();

キーワードvarが特定のシナリオで機能するかどうかは、変数、クラス、メソッドの名前やコードの複雑さなど、コードのコンテキストに大きく依存します。

個人的には、varキーワードを使用するのが好きです。これは、meよりも包括的です。しかし、私は変数に型にちなんで名前を付ける傾向があるので、実際に情報を失うことはありません。

そうは言っても、私は時々例外を作ります。それは複雑なものの性質であり、ソフトウェアは複雑ではないにしても何もありません。

1
Luis Perez