以前 なぜ非常に多くの例がvar
keywordを使用しているのを見るのか について質問し、匿名型にのみ必要であるにもかかわらずコードの作成に使用されるという回答を得ました 'より速く」/より簡単に、「ちょうど」という理由で。
このリンク(「C#3.0-Var Is n't Objec」)var
がILの正しい型にコンパイルされることがわかりました(記事の途中で表示されます) 。
私の質問は、ILコードがvar
キーワードを使用している場合、それ以上の量であり、それがどこでも使用されている場合、コードのパフォーマンスで測定可能なレベルを持つことにさえ近いでしょうか?
var
キーワードに追加のILコードはありません。結果のILは、非匿名型と同じでなければなりません。使用するつもりの型がわからないためにコンパイラがそのILを作成できない場合、コンパイラエラーが発生します。
唯一のトリックは、var
が、タイプを手動で設定する場合、インターフェイスまたは親タイプを選択した可能性がある正確なタイプを推測することです。
私の理解が変わったので、これを更新する必要があります。メソッドがインターフェイスを返す状況では、var
がパフォーマンスに影響を与える可能性があるが、正確な型を使用することになると考えています。たとえば、次の方法がある場合:
IList<int> Foo()
{
return Enumerable.Range(0,10).ToList();
}
メソッドを呼び出すには、次の3行のコードを検討してください。
List<int> bar1 = Foo();
IList<int> bar = Foo();
var bar3 = Foo();
3つすべてが期待どおりにコンパイルおよび実行されます。ただし、最初の2行はnotとまったく同じであり、3行目は1行目ではなく2行目に一致します。 Foo()
の署名はIList<int>
を返すことであるため、コンパイラはbar3
変数を作成します。
パフォーマンスの観点からは、ほとんど気付かないでしょう。ただし、 行目のパフォーマンスが1行目のパフォーマンスほど速くない場合があります の状況があります。 bar3
変数を使用し続けると、コンパイラは同じ方法でメソッド呼び出しをディスパッチできない場合があります。
ジッターがこの差を消去できる可能性があることに注意してください。 一般に、var
はパフォーマンスの観点から非ファクターであると考える必要があります。dynamic
変数。しかし、それがまったく違いをもたらさないと言うことは、それを誇張しているかもしれません。
Joelが言うように、コンパイラはcompile-timeでvar typeがどうあるべきかを決定します。事実上、これはコンパイラがキーストロークを保存するために実行するトリックです。
var s = "hi";
に置き換えられます
string s = "hi";
コンパイラによる ILが生成される前。生成されたILは、文字列を入力した場合と同じexactlyになります。
まだ誰もリフレクターに言及していないので...
次のC#コードをコンパイルする場合:
static void Main(string[] args)
{
var x = "hello";
string y = "hello again!";
Console.WriteLine(x);
Console.WriteLine(y);
}
次に、リフレクターを使用すると、次のようになります:
// Methods
private static void Main(string[] args)
{
string x = "hello";
string y = "hello again!";
Console.WriteLine(x);
Console.WriteLine(y);
}
答えは明らかに、実行時のパフォーマンスヒットではありません!
次の方法の場合:
private static void StringVsVarILOutput()
{
var string1 = new String(new char[9]);
string string2 = new String(new char[9]);
}
IL出力は次のとおりです。
{
.method private hidebysig static void StringVsVarILOutput() cil managed
// Code size 28 (0x1c)
.maxstack 2
.locals init ([0] string string1,
[1] string string2)
IL_0000: nop
IL_0001: ldc.i4.s 9
IL_0003: newarr [mscorlib]System.Char
IL_0008: newobj instance void [mscorlib]System.String::.ctor(char[])
IL_000d: stloc.0
IL_000e: ldc.i4.s 9
IL_0010: newarr [mscorlib]System.Char
IL_0015: newobj instance void [mscorlib]System.String::.ctor(char[])
IL_001a: stloc.1
IL_001b: ret
} // end of method Program::StringVsVarILOutput
それで、明確にするために、それは怠zyなコーディングスタイルです。選択肢があれば、ネイティブ型を好みます。余分な「ノイズ」を取り込んで、コード/デバッグ時に自分が考えているものを正確に読み書きできるようにします。 *肩をすくめる*
C#コンパイラは、コンパイル時にvar
変数の真の型を推測します。生成されたILに違いはありません。
あなたが読んだものを適切に理解したとは思わない。正しい型にコンパイルされると、そこにis違いはありません。私がこれを行うとき:
var i = 42;
コンパイラ知っているそれはintであり、私が書いたようにコードを生成する
int i = 42;
リンク先の投稿にあるように、同じタイプのcompiledになります。ランタイムチェックや、余分なコードを必要とするものではありません。コンパイラは、型が何である必要があるかを把握し、それを使用します。
Varを使用しても実行時のパフォーマンスコストは発生しません。ただし、コンパイラが型を推測する必要があるため、コンパイルのパフォーマンスコストがあると思われますが、これはほとんど無視できるでしょう。
コンパイラが自動型推論を実行できる場合、パフォーマンスに問題はありません。これらは両方とも同じコードを生成します
var x = new ClassA();
ClassA x = new ClassA();
ただし、型を動的に構築している場合(LINQ ...)、var
が唯一の質問であり、ペナルティとは何かを比較する他のメカニズムがあります。
私は常にWeb記事やガイドの執筆でWord変数を使用しています。
オンライン記事のテキストエディターの幅が小さい。
これを書くと:
SomeCoolNameSpace.SomeCoolClassName.SomeCoolSubClassName coolClass = new SomeCoolNameSpace.SomeCoolClassName.SomeCoolSubClassName();
上記のレンダリングされたプリコードテキストが長すぎてボックスから流れ出て、非表示になることがわかります。読者は完全な構文を見るために右にスクロールする必要があります。
だからこそ、私はWeb記事の執筆で常にキーワードvarを使用しています。
var coolClass = new SomeCoolNameSpace.SomeCoolClassName.SomeCoolSubClassName();
レンダリングされたプリコード全体が画面にぴったり収まります。
実際には、オブジェクトを宣言するためにvarを使用することはほとんどなく、オブジェクトをより速く宣言するためにインテリセンスに依存しています。
例:
SomeCoolNamespace.SomeCoolObject coolObject = new SomeCoolNamespace.SomeCoolObject();
しかし、メソッドからオブジェクトを返すには、varを使用してコードを高速に記述します。
例:
var coolObject = GetCoolObject(param1, param2);
「var」は、人々が好きまたは嫌いなもの(地域など)の1つです。ただし、地域とは異なり、匿名クラスを作成する場合はvarが絶対に必要です。
私にとって、varは次のようにオブジェクトを直接更新するときに意味があります。
var dict = new Dictionary<string, string>();
そうは言っても、簡単にできます:
Dictionary<string, string> dict =
newとintellisenseが残りをここで埋めます。
特定のインターフェイスのみを使用する場合は、呼び出すメソッドがインターフェイスを直接返さない限り、varを使用できません。
Resharperは、「var」を全面的に使用する側にいるようです。しかし、メソッドを呼び出している場合は読みにくく、名前によって何が返されるのかが明確ではないことに同意します。
var自体は速度を低下させませんが、これについては、多くの人が考えていない警告が1つあります。 var result = SomeMethod();
を実行すると、その後のコードは、さまざまなメソッドやプロパティなどを呼び出す場所に何らかの結果が返されることを期待しています。 SomeMethod()
がその定義を他のタイプに変更したが、それでも他のコードが期待していた契約を満たした場合、あなたは本当に厄介なバグを作成しました(もちろんユニット/統合テストがない場合)。
これは状況によって異なります。使用しようとすると、このコードが鳴ります。
式は「OBJECT」に変換され、パフォーマンスが大幅に低下しますが、それは孤立した問題です。
コード:
public class Fruta
{
dynamic _instance;
public Fruta(dynamic obj)
{
_instance = obj;
}
public dynamic GetInstance()
{
return _instance;
}
}
public class Manga
{
public int MyProperty { get; set; }
public int MyProperty1 { get; set; }
public int MyProperty2 { get; set; }
public int MyProperty3 { get; set; }
}
public class Pera
{
public int MyProperty { get; set; }
public int MyProperty1 { get; set; }
public int MyProperty2 { get; set; }
}
public class Executa
{
public string Exec(int count, int value)
{
int x = 0;
Random random = new Random();
Stopwatch time = new Stopwatch();
time.Start();
while (x < count)
{
if (value == 0)
{
var obj = new Pera();
}
else if (value == 1)
{
Pera obj = new Pera();
}
else if (value == 2)
{
var obj = new Banana();
}
else if (value == 3)
{
var obj = (0 == random.Next(0, 1) ? new Fruta(new Manga()).GetInstance() : new Fruta(new Pera()).GetInstance());
}
else
{
Banana obj = new Banana();
}
x++;
}
time.Stop();
return time.Elapsed.ToString();
}
public void ExecManga()
{
var obj = new Fruta(new Manga()).GetInstance();
Manga obj2 = obj;
}
public void ExecPera()
{
var obj = new Fruta(new Pera()).GetInstance();
Pera obj2 = obj;
}
}
ILSPYでの上記の結果。
public string Exec(int count, int value)
{
int x = 0;
Random random = new Random();
Stopwatch time = new Stopwatch();
time.Start();
for (; x < count; x++)
{
switch (value)
{
case 0:
{
Pera obj5 = new Pera();
break;
}
case 1:
{
Pera obj4 = new Pera();
break;
}
case 2:
{
Banana obj3 = default(Banana);
break;
}
case 3:
{
object obj2 = (random.Next(0, 1) == 0) ? new Fruta(new Manga()).GetInstance() : new Fruta(new Pera()).GetInstance();
break;
}
default:
{
Banana obj = default(Banana);
break;
}
}
}
time.Stop();
return time.Elapsed.ToString();
}
このコードを実行する場合は、以下のコードを使用して、時間の差を取得してください。
static void Main(string[] args)
{
Executa exec = new Executa();
int x = 0;
int times = 4;
int count = 100000000;
int[] intanceType = new int[4] { 0, 1, 2, 3 };
while(x < times)
{
Parallel.For(0, intanceType.Length, (i) => {
Console.WriteLine($"Tentativa:{x} Tipo de Instancia: {intanceType[i]} Tempo Execução: {exec.Exec(count, intanceType[i])}");
});
x++;
}
Console.ReadLine();
}
よろしく