10

var私が読んでいる本では、暗黙の型付けにより、キーワードを使用しなかった場合よりも次のコードが明確になると述べています。

var words = new[] { "a", "b", null, "d" };

foreach (var item in words)
{
    Console.WriteLine(item);
}

私にはその逆のように思えます。string代わりに使用すると、コードの読者は、変数が定義されているコードを検索する代わりに、foreach ループ内の文字列であることがすぐにわかります。

暗黙の型付けにより、上記のコードがどのように明確になりますか?

補遺

その本はC# 3.0 - Die Neuerungen です。schnell + kompaktはドイツ語で、実際のテキストは次のとおりです。

Das Schluesselwort var kann auch beim Durchlaufen von foreach-Schleifen verwendet werden, um somit den Code uebersichtlicher und einfacher zu gestalten. Besonders bei komplexen Typen kann man auf diese Art und Weise Programmierfehler verhindern.

ここに私の翻訳があります:

var キーワードは、foreach ループを反復処理するときにも使用できるため、コードの作成が簡単になります。特に複雑な型を使用する場合、これによりプログラミング エラーを防ぐことができます。

わかりました、さらに詳しく読んでみると、彼は実際varに、foreach ループでコードを作成しやすくすることはできますが、必ずしも読みやすくするとは限りません。

4

13 に答える 13

12

個人的には、私はあなたに同意します。私が使用する言葉が明確かどうかはわかりませんが、特定の状況では、varキーワードは確かにそれをよりきれいにすることができます。

var myClass = new ExtremelyLongClassNameIWouldntWantToTypeTwice();
于 2010-08-06T10:03:36.173 に答える
12

Python、JavaScript、Ruby、F#、Haskell などの開発者は影響を受けないように見えるのに、C# と Java のプログラマーだけがコードのコンテキストから情報を抽出することを妨げられるという問題に苦しんでいるように見えるのは奇妙だと思います。彼らはうまくやっているように見えるのに、なぜ私たち C# プログラマーはこの議論をする必要があるのでしょうか?

前述の明示的な型宣言がずさんまたは怠惰である場合、それは高品質で読み取り可能な Python コードがないということですか? 実際、多くの人が Python の読みやすさを称賛していませんか? そして、JavaScript の動的型付けについて私をイライラさせることがたくさんありますが、明示的な型宣言の欠如はその 1 つではありません。

静的に型付けされた言語での型推論は、例外ではなく標準であるべきです。これにより、視覚的な煩雑さと冗長性が軽減されますが、派生型が少ないために型を明示的に指定する場合の意図が明確になります ( )IList<int> list = new List<int>();

var次のように反論する人もいるかもしれません。

var c = SomeMethod();

それには、変数にもっとわかりやすい名前を付けるべきだと思います。

改善:

var customer = SomeMethod();

より良い:

var customer = GetCustomer();

明示的な型付けを試してみましょう:

Customer customer = GetCustomer();

以前は持っていなかったが、今はどのような情報を持っていますか? タイプが であることは確かにわかりましCustomerたが、それはすでに知っていましたよね?customer既にコードに精通している場合は、変数の名前だけで、 で期待できるメソッドとプロパティがわかります。コードにまだ慣れていない場合は、どのメソッドにどのような方法があるかわかりませんCustomer。ここでの明示的な型には何の価値もありません。

おそらく一部の反対者はvar、上記の例でvarは害がないことを認めているかもしれません。Customerしかし、メソッドが、 またはOrderのような単純でよく知られている型ではなく、ある種の Dictionary のような処理された値を返す場合はどうなるでしょうか? 何かのようなもの:

var ordersPerCustomer = GetOrdersPerCustomer();

それが何を返すかはわかりません。辞書、リスト、配列など、実際には何でもかまいません。しかし、それは問題ですか?Customerコードから、顧客の反復可能なコレクションがあり、それぞれに反復可能なコレクションが含まれていると推測できますOrderここのタイプはあまり気にしません。知っておくべきことはわかっています。間違っていることが判明した場合、それはメソッドの名前で誤解を招く原因であり、明示的な型宣言では修正できないものです。

明示的なバージョンを見てみましょう:

IEnumerable<IGrouping<Customer,Order>> ordersPerCustomer = GetOrdersPerCustomer();

あなたのことはわかりませんが、ここから必要な情報を抽出するのははるかに難しいと思います. <少なくとも、実際の情報 (変数名) を含むビットがさらに右にあるため、それを見つけるのに時間がかかります>。実際の型は価値がありません。特に、それを理解するには、これらのジェネリック型が何をするかを知る必要があるためです。

名前だけでは、メソッドの機能や変数の内容がわからない場合は、より適切な名前を付ける必要があります。それは、それがどのタイプであるかを見るよりもはるかに価値があります。

明示的な型付けは必要ありません。必要な場合は、型推論ではなく、コードに問題があります。他の言語も明らかにそれを必要としないので、それは必要ありません。

そうは言っても、私は や のような「プリミティブ」に明示的な型付けを使用する傾向がありintますstring。しかし、正直なところ、それは意識的な決定ではなく、習慣の問題です。mただし、数値の場合、 として入力したいリテラル数値にを追加するのを忘れた場合、型推論はあなたを台無しにする可能性がありますdecimal。これは簡単に行うことができますが、コンパイラーは誤って精度を失うことを許可しないため、そうではありません。実際の問題。実際、varどこでも使用していれば、私が取り組んでいる大規模なアプリケーションで、整数から 10 進数への数量の変更がはるかに簡単になったでしょう。

これは のもう 1 つの利点ですvar。変更を反映するためにどこでも型を更新する必要がなく、迅速な実験が可能です。上記の例を に変更したい場合はDictionary<Customer,Order>[]、実装を変更するだけで、それを呼び出したすべてのコードvarは引き続き機能します (少なくとも変数宣言は)。

于 2010-08-07T00:34:09.680 に答える
9

この場合、そうではありません。もちろん、これは私の主観的な意見です。タイプが次のように同じ行の他の場所にある場合にのみ使用します。

var words = new List<String>();

私は var が好きですが、タイプが何であるかが明確でないため、あなたの例のようには使用しません。

于 2010-08-06T10:04:05.123 に答える
5

ノイズ/冗長性が少ないという意味で、より明確です。の型は、コンパイラ開発者の両方がステートメントからwords簡単に推測できます。後者はコードを視覚的に乱雑にする可能性があるため、代わりにSoが使用されます。new[] { ... }varstring[]

透明感という意味ではよりクリアです。列挙可能な型である限り、実際の値を他の型のインスタンスと交換できます。を使用しなかった場合はvar、例の両方の宣言ステートメントを変更する必要があります。

適切な変数名を使用する必要があるため、より明確です。をvar使用すると、型宣言を使用して変数の内容を示すことができないため、わかりやすい名前を使用する必要があります。変数を宣言するのは 1 回だけですが、何度も使用する可能性があるため、名前で変数の内容を把握できるようにすることをお勧めします。この観点からword、ループ変数名のより良い選択だったでしょう。

上記の推論は、著者の観点から行われていることに注意してください。それは必ずしも私の個人的な意見を反映しているわけではありません:)

補遺に関する編集:

foreach前に述べたように、すべてのループを更新することなく、基になるコレクション タイプを交換できます。これにより、コードの作成と変更が容易になりますが、必ずしもプログラミング エラーが防止されるわけではありません。Word単純な文字列の代わりとしてクラスを導入した後、両方のケースを見てみましょう。

キーワードを使用しない場合、コンパイラはエラーをキャッチします。var

var words = new[] { new Word("a"), new Word("b"), null, new Word("d") };

// The compiler will complain about the conversion from Word to string,
// unless you have an implicit converion.
foreach (string word in words)
{
    Console.WriteLine(word);
}

を使用するvar、コードはエラーなしでコンパイルされますが、Wordクラスが (適切に) 実装されていない場合、プログラムの出力はまったく異なりますToString()

var words = new[] { new Word("a"), new Word("b"), null, new Word("d") };

foreach (var word in words)
{
    Console.WriteLine(word); // Output will be different.
}

そのため、場合によっては、 を使用すると微妙なバグが発生する可能性がありvarます。そうしないと、コンパイラによって検出されたはずです。

于 2010-08-06T11:05:35.320 に答える
3

シンタックス シュガーを示す多くの例が傾向があるため、この例は貧弱です。シンタックス シュガーは物事が複雑な場合に役立ちますが、誰も複雑な例を好みません。

を使用する必要がある場合は 2 つあり、使用しvarなければならない場合は 1 つです。

あなたが望むかもしれない場所:

  1. 問題空間を探索しているときに、関係する型をすばやく切り替えるときに、実験的なコードで役立ちます。
  2. IGrouping<int, IEnumerable<IGrouping<Uri, IGrouping<int, string>>>>これは、複雑なクエリや列挙操作内の中間状態で特に発生する可能性があるような、複雑なジェネリックベースの型で役立ちます。

個人的にはvar、正確なタイプを気にしない人がそれを読むのに費用がかからないため、より複雑なフォームを使用することを好みます (「複雑なグループ化タイプ」と考えてスキップすることができます)。自分で解決しなくても気にしません。

必要な場所:

匿名型を扱う場合、次のようなコードで:

var res = from item in src select new {item.ID, item.Name};    
foreach(var i in res)    
    doSomething(i.ID, i.Name);

ここで、res は匿名型の IEnumerable または IQueryable であり、i はその匿名型です。型には名前がないため、明示的に宣言することはできません。

この最後のケースでは、それはシンタックス シュガーではなく、実際に重要です。

関連する不満は、SharpDevelop が独自の編集中形式の var を使用していたことです。次のように入力できます。

? words = new string[] { "a", "b", null, "d" };

そして、セミコロンで、エディターは次のように生成します。

string[] words = new string[] { "a", "b", null, "d" };

これにより、(特により複雑なケースでは) 明示的なコードを生成するだけでなく、タイピング速度の利点が得られました。var が概念的に同じことを行うため、彼らはこれを削除したようですが、明示的な形式への入力ショートカットが失われたのは残念です。

于 2010-08-06T11:22:17.357 に答える
3

ここでクリーンとは、冗長性が低いことを意味します。コンパイラがオブジェクトの型が であると推測するのは簡単なので、string[]明示的に指定するのは冗長であると見なされます。ただし、ご指摘のとおり、コードを読んでいる人間にはそれほど明白ではないかもしれません。

于 2010-08-06T10:05:50.413 に答える
2

暗黙的な型付けの使用はガイドラインであり、法律ではありません。

あなたが提起したのは、暗黙的が確かに理想的ではない極端な例です。

于 2010-08-06T10:04:35.177 に答える
2

コードをより明確にします

  1. 非常に長い名前のクラスがあります。
  2. linq クエリがあります。
于 2010-08-06T10:12:58.437 に答える
2

F# を使い始めるまでは、C# の暗黙的な型付けの良い面を本当に理解していなかったと思います。F# には、いくつかの点で C# の暗黙的な型指定に似た型推論メカニズムがあります。F# では、型推論の使用はコード設計の非常に重要な側面であり、単純な例でもコードをより読みやすくすることができます。F# で型推論を使用することを学んだことで、暗黙の型付けによって C# がより読みやすくなり、混乱を招くのではなく、これらの状況を理解するのに役立ちました。(Linq のケースはかなり明白だと思いますが、多くのケースはそうではありません。)

これは、re.C# という質問への回答というよりも、F# のプラグインのように聞こえると思いますが、単純な一連のルールに限定できるものではありません。読みやすさやメンテナンスなどを考えるとき、コードを新しい目で見ることは学習です。(それと、F# のプラグインのようなものかもしれません (笑))

于 2010-08-06T16:42:02.917 に答える
1

このコードをより明確にしたい場合は、var を削除する代わりに new を展開することをお勧めします。

var words = new string[] { "a", "b", null, "d" };

Resharper は、その例で冗長なコードを削除するためのヒントを提供しますが、必要に応じてそれらのヒントをオフにすることができます。

var を使用する理由は、多くの場合、ローカル変数の型識別子は冗長であり、冗長なコードを削除する必要があるということです。冗長なコードを削除することで、実際に気にするケースをより明確にすることができます。たとえば、ローカル変数に特定のインターフェイス タイプを強制する場合です。

ISpecificInterface foo = new YourImplementation()
于 2010-08-06T10:17:58.803 に答える
0

When you need to change your code, you'd have to do it in less places. No more Dictionary or longer type declarations, no more Some.Very.Long.Class.With.Very.Long.Path<string> declaration = functionParameter[index], etc.

Although I do agree that when it is used in other situations than small methods, it might get very confusing.

于 2010-08-06T10:08:35.853 に答える
0

明示的な型付けの主な利点は、変数の型をコードで確認するだけで可能になるという私の見解です。そのため、可読性が向上します。

暗黙的な型付けの主な利点は次のとおりです。

  • 特に長い型名 (クラス、インターフェース) のプログラム テキストを減らし、読みやすさを向上させます。
  • メソッドの戻り値の型が変更されたときの変更が少なくなります。

どちらのオプションも可読性を向上させるように見えます。

したがって、それはあなたの好みと、おそらくチームのプログラミングガイドラインにも依存すると思います。IDE での現在の (リファクタリング) ツールのサポートにより、型名の変更がはるかに簡単になりました (非常に簡単です)。そのため、暗黙の型付けが変更を減らす理由は、労力の観点から事実上なくなりました。

私が提案したいのは、あなたにとって最善のことをすることです。正解も不正解もありません。それぞれのアプローチをしばらく試してから (たとえば、お気に入りのリファクタリング ツールのオプションを構成するなど)、開発者としての生活を楽にするものを使用してください。

于 2010-08-06T11:24:30.157 に答える
0

var の使いすぎは実際に有害である可能性があり、実際の型が非常に単純な場合は、そのように記述する必要があるという重要なアイデアを取り上げました。

ただし、var は、より大きな継承階層とテンプレートを扱う場合に役立ちます。「どうでもいい - ただデータをくれ」と読むことも できる正確なタイプを明示的に釘付けにする必要がある場合、扱いにくいだけでなく、見つけるのも困難です。

たとえば、SQL と対話するためのいくつかの種類の DataReader のテンプレート ラッパーを想像してみてください。これにより、引き続き効率的 (sproc の呼び出し、結果の取得、完了) でありながら、ハウスキーピングの負担 (リーダーと接続のクローズ、再試行、またはエラーなど)。それを使用するコードは、できるだけ短い構文を持つように作成された1つの関数を呼び出すだけで、C++のスマートポインターのように機能するラッパーを返します-コードのDataReaderのように機能しますが、横向きのものもすべて処理します. したがって、次のように簡単に見えます。

using (var r = S.ExecuteReader("[MySproc]", params))
{
    while ((+r).Read())
    (
       // get my data and be done
    )
} // at this point wrapper cleans up everything

このような場合、ラッパーがどのように命名および宣言されているかをあまり気にしないだけでなく、その名前を知ることさえ気にしません-コードにとっては無関係です。あなたはただあなたのくそったれのデータが欲しいだけで、誰かの長い宣言を扱わずに続けてください:-)。

文字通り、完全な型宣言を気にするときと気にしないときを選択できます。すべてかゼロかということではなく、両方のスタイルを使用していることに気付くでしょう。

ラムダ式を使用する場合は、ラムダ式を使用することをお勧めします。C# でラムダを使用する場合、ほとんどの場合、一度実行される短くてコンパクトなコードが必要であり、通常のメソッドに変換する手間がかからないか、ホスト メソッドのローカル変数に依存するためです。

ああ、VS エディターでさえ完全な型を推測し、オートコンプリートを提供し、できないものを使用しようとすると文句を言うので、var は型の安全性をまったく壊しません (新しい C++ も var と同等です -お久しぶりです)。

于 2010-08-09T06:13:08.453 に答える