37

内部監査では、キーワードを使用する代わりに、明示的な変数型宣言を使用することを提案していますvarvar彼らは、 「場合によっては予期しない結果につながる可能性がある」と主張しています。

var明示的な型宣言と、コードがMSILにコンパイルされた後の使用との違いを認識していません。

監査人は尊敬されている専門家なので、私はそのような提案を単純に拒否することはできません。

4

18 に答える 18

50

これはどう...

double GetTheNumber()
{
    // get the important number from somewhere
}

そして他の場所...

var theNumber = GetTheNumber();
DoSomethingImportant(theNumber / 5);

そして、将来のある時点で、誰かGetTheNumberが整数のみを返すことに気付いたので、それをリファクタリングして、intではなく返すようにしdoubleます。

バン!以前は浮動小数点演算であったものが、誰にも気付かれることなく整数演算になっているため、コンパイラエラーは発生せず、予期しない結果が発生し始めます。

そうは言っても、この種のことはユニットテストなどで捕らえられるべきですが、それでも潜在的な落とし穴です。

于 2010-09-07T12:32:37.030 に答える
22

私はこのスキームに従う傾向があります:

var myObject = new MyObject(); // OK as the type is clear

var myObject = otherObject.SomeMethod(); // Bad as the return type is not clear

リターンタイプがSomeMethod変更された場合でも、このコードはコンパイルされます。最良の場合、コンパイルエラーがさらに発生しますが、最悪の場合(myObject使用方法によっては)発生しない場合があります。その場合におそらく発生するのは、追跡が非常に難しい実行時エラーです。

于 2010-09-07T12:02:29.553 に答える
13

varは動的タイプではなく、単にシンタックスシュガーです。これに対する唯一の例外は、匿名タイプの場合です。 MicrosoftDocsから

多くの場合、varの使用はオプションであり、構文上の便宜にすぎません。ただし、変数が匿名型で初期化される場合、後でオブジェクトのプロパティにアクセスする必要がある場合は、変数をvarとして宣言する必要があります。

タイプを暗黙のタイプとは異なるものとして明示的に定義しない限り、一度ILにコンパイルしても違いはありません(ただし、なぜそうするのかはわかりません)。コンパイラーでは、varで宣言された変数の型をいつでも変更することはできません。

Microsoftのドキュメントから(再び)

暗黙的に型付けされたローカル変数は、自分で型を宣言したかのように強く型付けされますが、コンパイラーが型を決定します

場合によっては、varは読みやすさを妨げる可能性があります。その他のMicrosoftドキュメントの状態:

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

于 2010-09-07T12:01:03.797 に答える
13

場合によっては、予期しない結果が生じる可能性があります。私var自身はファンですが、これはうまくいかない可能性があります。

var myDouble = 2;
var myHalf = 1 / myDouble;

明らかに、これは間違いであり、「予期しない結果」ではありません。しかし、それ落とし穴です...

于 2010-09-07T12:01:41.303 に答える
8

非ジェネリックな世界では、ループvar内などで暗黙的な変換が発生するたびに、型の代わりに使用すると異なる動作が発生する可能性があります。foreach

以下の例では、からobjectへの暗黙の変換XmlNodeが行われます(非ジェネリックIEnumeratorインターフェイスはのみを返しますobject)。ループ変数の明示的な宣言をキーワードに置き換えるだけでvar、この暗黙的な変換は行われません。

using System;
using System.Xml;

class Program
{
    static void Foo(object o)
    {
        Console.WriteLine("object overload");
    }

    static void Foo(XmlNode node)
    {
        Console.WriteLine("XmlNode overload");
    }

    static void Main(string[] args)
    {
        XmlDocument doc = new XmlDocument();
        doc.LoadXml("<root><child/></root>");

        foreach (XmlNode node in doc.DocumentElement.ChildNodes)
        {
            Foo(node);
        }

        foreach (var node in doc.DocumentElement.ChildNodes)
        {
            // oops! node is now of type object!
            Foo(node);
        }
    }
}

varその結果、このコードは、使用したタイプと明示的なタイプのどちらを使用したかに応じて、実際には異なる出力を生成します。オーバーロードを使用すると実行されます。それ以外の場合はvarオーバーロードが実行されます。したがって、上記のプログラムの出力は次のようになります。Foo(object)Foo(XmlNode)

XmlNodeの過負荷
オブジェクトの過負荷

この動作は、C#言語仕様に完全に準拠していることに注意してください。唯一の問題は、予想varとは異なるタイプ(object)を推論することと、この推論がコードを見ても明らかではないことです。

短くするためにILを追加しませんでした。ただし、必要に応じてildasmを調べて、コンパイラが2つのforeachループに対して実際に異なるIL命令を生成することを確認できます。

于 2010-09-07T12:17:08.067 に答える
7

varC#言語には、の使用よりもはるかに複雑な微妙な点があるため、「場合によっては予期しない結果につながる可能性がある」ため、使用してはならないというのは奇妙な主張ですvar

これらの1つは、匿名メソッドの実装の詳細であり、R#警告「変更されたクロージャへのアクセス」につながる可能性があり、コードを見ると期待するものとはまったく異なる動作になります。varいくつかの文で説明できるものとは異なり、この動作には、完全に説明するための逆アセンブラの出力を含む3つの長いブログ投稿が必要です。

これは、匿名メソッド(つまり、デリゲート、ラムダ)や、LinqやParallelFXなどのそれらに依存するライブラリも使用してはならないことを意味します。これは、特定の奇妙な状況では、動作が期待どおりにならない可能性があるためです。

もちろん違います。

つまり、書いている言語を理解し、その制限とエッジケースを理解し、期待どおりに機能することをテストする必要があります。「場合によっては予期しない結果につながる可能性がある」という理由で言語機能を除外すると、使用する言語機能がほとんどなくなることになります。

彼らが本当にトスについて議論したいのであれば、あなたのバグの多くがの使用に直接起因する可能性がvarあり、明示的な型宣言がそれらを防いだであろうことを実証するように彼らに依頼してください。すぐに返事が来るとは思えません。

于 2010-09-07T17:54:07.633 に答える
4

彼らは、varの使用は「場合によっては予期しない結果につながる可能性がある」と主張しています。場合によっては予期しない結果につながる可能性があります。

「コードを読んで何をしているのかわからない」という予想外の場合は、そうです、予想外の結果につながる可能性があります。コンパイラは、変数の周囲に記述されたコードに基づいて、変数を作成するタイプを認識している必要があります。

varキーワードは、コンパイル時の機能です。コンパイラーは、宣言に適切な型を入れます。これが、次のようなことができない理由です。

var my_variable = null
or
var my_variable;

varキーワードは、コード自体で定義する必要のある情報が少ないため、優れています。コンパイラーは、それがあなたのために何をすべきかを理解します。これは、インターフェイスを使用するときに常にプログラミングするのとほぼ同じです(インターフェイスのメソッドとプロパティは、varで定義された変数の宣言スペース内で使用するものによって定義されます)。変数の型を変更する必要がある場合(当然のことながら)、変数宣言の変更について心配する必要はありません。コンパイラーがこれを処理します。これは些細なことのように聞こえるかもしれませんが、関数の戻り値を変更する必要があり、その関数がプログラム全体で使用されている場合はどうなりますか。varを使用しなかった場合は、変数が呼び出されるすべての場所を見つけて置き換える必要があります。varキーワードを使用すると、それについて心配する必要はありません。

于 2010-09-07T12:01:40.430 に答える
4

ガイドラインを考え出すとき、監査人がしなければならないように、人々に単に賢明正しいことをするように言うのではなく、愚か者の安全の側で誤りを犯したほうがおそらく良いでしょう。手元の状況の評価に基づくもの

「コードのどこにも使用しないでください」と言うだけvarで、コーディングガイドラインの多くのあいまいさを取り除くことができます。これにより、いつこれを行うか、いつ行うかという問題を解決することなく、コードのルックアンドフィールがより標準化されるはずです。

私は個人的に大好きvarです。すべてのローカル変数に使用します。いつも。結果のタイプが明確でない場合、これはの問題ではなくvar、変数の初期化に使用されるメソッド(の名前付け)の問題です。

于 2010-09-07T12:06:52.337 に答える
1

var変数がどのタイプであるかが明確な場合、またはタイプをまったく知る必要がない場合にのみ使用します(たとえば、GetPerson()はPersonPerson_Classなどを返す必要があります)。

varプリミティブ型、列挙型、文字列には使用しません。また、値型は代入によってコピーされるため、変数の型を明示的に宣言する必要があるため、値型には使用しません。

監査人のコメントについては、私たちが毎日行っているようにコード行を追加すると、 「場合によっては予期しない結果につながる」と言えます。この引数の有効性は、私たちが作成したバグによってすでに証明されているため、それを防ぐためにコードベースを永久にフリーズすることをお勧めします。

于 2010-09-08T19:41:58.280 に答える
1

varキーワードの使用に関しては、単純な原則に従います。事前にタイプがわかっている場合は、varを使用しないでください。ほとんどの場合、匿名型を返したいので、linqでvarを使用します。

于 2010-09-07T11:57:51.400 に答える
1

明らかに宣言がある場合に使用するのに最適なvar

ArrayList<Entity> en = new ArrayList<Enity>()

読みやすさを複雑にします

var en = new ArrayList<Entity>()

怠惰で明確なコード、私はそれが好きです

于 2010-09-07T20:12:45.680 に答える
0

varを使用した変数宣言と明示的に指定された変数宣言のIL出力にまったく違いはありません(これはリフレクターを使用して証明できます)。すべてを明示的に指定したいので、私は通常var、長いネストされたジェネリック型、ループ、および匿名型にのみ使用します。foreach他の人は異なる好みを持っているかもしれません。

于 2010-09-07T12:01:53.517 に答える
0

varは、明示的な型宣言を使用するための省略表記です。

varは特定の状況でのみ使用できます。varを使用する場合は、宣言時に変数を初期化する必要があります。後で別のタイプの変数を変数に割り当てることはできません。

多くの人が「var」キーワードをVB6の「Variant」データ型と混同する傾向があるように思われます。

于 2010-09-07T12:02:38.210 に答える
0

明示的な変数宣言を使用することに関して私が見る「唯一の」利点は、適切に選択された型名を使用して、コードの意図をはるかに明確に示すことです(これは他の何よりも重要です)。varキーワードの利点は、実際にはPieterが言ったことです。

于 2010-09-07T12:04:01.157 に答える
0

タイプがどうなるかがわかっている場合、varの使用は怠惰なコードです。読みやすく、すっきりしています。たくさんのコードを見るときは、より簡単でクリーンな方が常に優れています

于 2010-09-07T12:01:39.943 に答える
0

また、最後にDを付けずにダブルスを宣言すると、問題が発生すると思います。リリースバージョンをコンパイルするとき、コンパイラは精度を考慮しないため、スペースを節約するためにdoubleを取り除き、floatにする可能性があります。

于 2010-09-07T21:09:02.793 に答える
0

varは、指定できる静的型と同じものにコンパイルされます。コード内でそのタイプを明示する必要がなくなるだけです。これは動的タイプではなく、実行時に変更されない/変更されません。foreachループで使用すると非常に便利です。

foreach(var item in items)
{
item.name = ______;
}

列挙型を操作する場合、特定のタイプが不明であり、検索に時間がかかることがあります。静的タイプの代わりにvarを使用すると、同じ結果が得られます。また、varを使用すると、リファクタリングが容易になることもわかりました。別のタイプの列挙を使用する場合、foreachを更新する必要はありません。

于 2010-09-10T08:06:15.530 に答える
0

varを使用すると、論理プログラミングエラーが隠される可能性があります。そうしないと、コンパイラまたはIDEから警告が表示されます。この例を参照してください。

float distX = innerDiagramRect.Size.Width / (numObjInWidth + 1);

ここでは、計算のすべてのタイプがであり、結果を変数intで取得するため、分数が失われる可能性について警告が表示されます。float

varの使用:

var distX = innerDiagramRect.Size.Width / (numObjInWidth + 1);

distXのタイプはとしてコンパイルされているため、ここでは警告は表示されませんint。float値を使用する場合、これは論理エラーでありdivide by zero、この最初の計算の結果が1未満の場合に後の計算で例外がトリガーされない限り、実行時に特定するのは困難です。

于 2012-09-07T07:17:34.120 に答える