Kode berikut menghasilkan penggunaan variabel lokal "numberOfGroups" yang tidak ditetapkan :
int numberOfGroups;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
numberOfGroups = 10;
}
Namun, kode ini berfungsi dengan baik (meskipun, ReSharper mengatakan = 10
itu berlebihan):
int numberOfGroups = 10;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
numberOfGroups = 10;
}
Apakah saya melewatkan sesuatu, atau kompiler tidak menyukai saya ||
?
Saya telah mempersempit ini menjadi dynamic
penyebab masalah ( options
adalah variabel dinamis dalam kode saya di atas). Pertanyaannya masih ada, mengapa saya tidak bisa melakukan ini ?
Kode ini tidak dapat dikompilasi:
internal class Program
{
#region Static Methods
private static void Main(string[] args)
{
dynamic myString = args[0];
int myInt;
if(myString == null || !int.TryParse(myString, out myInt))
{
myInt = 10;
}
Console.WriteLine(myInt);
}
#endregion
}
Namun, kode ini tidak :
internal class Program
{
#region Static Methods
private static void Main(string[] args)
{
var myString = args[0]; // var would be string
int myInt;
if(myString == null || !int.TryParse(myString, out myInt))
{
myInt = 10;
}
Console.WriteLine(myInt);
}
#endregion
}
Saya tidak menyadari dynamic
akan menjadi faktor dalam hal ini.
out
parameter Anda sebagai masukanout
param. Sangat menarik untuk mempertimbangkan kode pembantu apa yang harus dihasilkan kompilator untuk menghindari masalah, atau bahkan jika itu memungkinkan.Jawaban:
Saya cukup yakin ini adalah bug kompiler. Temuan bagus!
Sunting: ini bukan bug, seperti yang ditunjukkan Quartermeister; dynamic mungkin menerapkan
true
operator aneh yang mungkin menyebabkany
tidak pernah diinisialisasi.Ini repro minimal:
Saya tidak melihat alasan mengapa itu ilegal; jika Anda mengganti dynamic dengan bool, itu akan dikompilasi dengan baik.
Saya sebenarnya akan bertemu dengan tim C # besok; Saya akan menyebutkannya kepada mereka. Maaf atas kesalahannya!
sumber
d
mungkin dari tipe dengantrue
operator yang kelebihan beban . Saya telah memposting jawaban dengan contoh di mana tidak ada cabang yang diambil.Mungkin saja variabel tidak ditetapkan jika nilai ekspresi dinamis adalah tipe dengan operator yang kelebihan beban
true
.The
||
Operator akan memanggiltrue
operator untuk memutuskan apakah untuk mengevaluasi sisi kanan, dan kemudianif
pernyataan akan memanggiltrue
operator untuk memutuskan apakah untuk mengevaluasi tubuhnya. Untuk normalbool
, ini akan selalu mengembalikan hasil yang sama sehingga tepat satu akan dievaluasi, tetapi untuk operator yang ditentukan pengguna tidak ada jaminan seperti itu!Membangun dari repro Eric Lippert, berikut adalah program singkat dan lengkap yang menunjukkan kasus di mana tidak ada jalur yang akan dieksekusi dan variabel akan memiliki nilai awalnya:
sumber
d
dievaluasi dua kali? (Saya tidak membantah bahwa itu jelas adalah , karena Anda telah menunjukkan.) Saya akan diharapkan hasil dievaluasi daritrue
(dari doa operator pertama, menyebabkan oleh||
) untuk "diteruskan" keif
pernyataan. Itu pasti yang akan terjadi jika Anda menempatkan pemanggilan fungsi di sana, misalnya.d
dievaluasi hanya sekali, seperti yang Anda harapkan. Ini adalahtrue
operator yang sedang dipanggil dua kali, sekali oleh||
dan sekali olehif
.var cond = d || M(out y); if (cond) { ... }
. Pertama kita evaluasid
untuk mendapatkanEvilBool
referensi objek. Untuk mengevaluasi||
, pertama-tama kita memanggilEvilBool.true
dengan referensi itu. Itu mengembalikan nilai true, jadi kami mengalami hubungan pendek dan tidak memanggilM
, dan kemudian menetapkan referensi kecond
. Kemudian, kami melanjutkan keif
pernyataan. Theif
pernyataan mengevaluasi kondisinya dengan meneleponEvilBool.true
.Dari MSDN (penekanan saya):
Karena kompilator tidak memeriksa atau menyelesaikan operasi apa pun yang berisi ekspresi tipe dinamis, ia tidak dapat memastikan bahwa variabel akan ditetapkan melalui penggunaan
TryParse()
.sumber
numberGroups
ditetapkan (diif true
blok), jika tidak, kondisi kedua menjamin penugasan (viaout
).myString == null
(hanya mengandalkanTryParse
).if
ekspresi) melibatkan sebuahdynamic
variabel, itu tidak diselesaikan pada waktu kompilasi (oleh karena itu kompilator tidak dapat membuat asumsi tersebut).