Saya mendapatkan kesalahan di atas dan tidak dapat menyelesaikannya. Saya mencari di Google sedikit tetapi tidak bisa menyingkirkannya.
Skenario:
Saya memiliki kelas BudgetAllocate yang propertinya adalah anggaran yang berjenis ganda.
Di dataAccessLayer saya,
Di salah satu kelas saya, saya mencoba melakukan ini:
double.TryParse(objReader[i].ToString(), out bd.Budget);
Yang melempar kesalahan ini:
Properti atau pengindeks tidak boleh dikirimkan sebagai parameter keluar atau ref pada waktu kompilasi.
Saya bahkan mencoba ini:
double.TryParse(objReader[i].ToString().Equals(DBNull.Value) ? "" : objReader[i].ToString(), out bd.Budget);
Segala sesuatu yang lain berfungsi dengan baik dan referensi antar lapisan ada.
c#
.net
error-handling
Pratik
sumber
sumber
DataGrid
untuk diisi dari kemudian datang untuk mempelajarinya hanya secara otomatis dengan properti. Beralih ke properti merusak beberapa parameter ref yang saya gunakan di bidang saya. Harus mendefinisikan variabel lokal untuk melakukan parsing.Jawaban:
kamu tidak bisa menggunakan
double.TryParse(objReader[i].ToString(), out bd.Budget);
ganti bd.Budget dengan beberapa variabel.
double k; double.TryParse(objReader[i].ToString(), out k);
sumber
Orang lain telah memberi Anda solusinya, tetapi mengapa ini perlu: properti hanyalah gula sintaksis untuk suatu metode .
Misalnya, ketika Anda mendeklarasikan properti yang dipanggil
Name
dengan getter dan setter, di bawah tenda kompilator sebenarnya menghasilkan metode yang dipanggilget_Name()
danset_Name(value)
. Kemudian, saat Anda membaca dan menulis ke properti ini, compiler menerjemahkan operasi ini menjadi panggilan ke metode yang dihasilkan tersebut.Saat Anda mempertimbangkan ini, menjadi jelas mengapa Anda tidak dapat meneruskan properti sebagai parameter output - Anda sebenarnya akan meneruskan referensi ke metode , bukan referensi ke
obyeksebuah variabel , yang merupakan apa mengharapkan parameter output.Kasus serupa terjadi untuk pengindeks.
sumber
Ini adalah kasus abstraksi yang bocor. Properti sebenarnya adalah metode, get dan set aksesor untuk pengindeks dikompilasi ke metode get_Index () dan set_Index. Kompilator melakukan pekerjaan yang hebat menyembunyikan fakta itu, secara otomatis menerjemahkan sebuah tugas ke sebuah properti ke metode set_Xxx () yang sesuai misalnya.
Tapi ini akan gagal saat Anda meneruskan parameter metode dengan referensi. Itu membutuhkan kompilator JIT untuk meneruskan pointer ke lokasi memori dari argumen yang diteruskan. Masalahnya, tidak ada, menetapkan nilai properti memerlukan pemanggilan metode penyetel. Metode yang dipanggil tidak dapat membedakan antara variabel yang diteruskan vs properti yang diteruskan dan karenanya tidak dapat mengetahui apakah pemanggilan metode diperlukan.
Perlu dicatat bahwa ini benar-benar berfungsi di VB.NET. Sebagai contoh:
Class Example Public Property Prop As Integer Public Sub Test(ByRef arg As Integer) arg = 42 End Sub Public Sub Run() Test(Prop) '' No problem End Sub End Class
Kompiler VB.NET memecahkan masalah ini dengan secara otomatis menghasilkan kode ini untuk metode Jalankan, yang dinyatakan dalam C #:
int temp = Prop; Test(ref temp); Prop = temp;
Yang merupakan solusi yang dapat Anda gunakan juga. Tidak begitu yakin mengapa tim C # tidak menggunakan pendekatan yang sama. Mungkin karena mereka tidak ingin menyembunyikan panggilan pengambil dan penyetel yang berpotensi mahal. Atau perilaku yang sama sekali tidak dapat didiagnosis yang akan Anda dapatkan ketika penyetel memiliki efek samping yang mengubah nilai properti, mereka akan menghilang setelah penetapan. Perbedaan klasik antara C # dan VB.NET, C # adalah "tidak ada kejutan", VB.NET adalah "buatlah bekerja jika Anda bisa".
sumber
Tempatkan parameter out ke dalam variabel lokal dan kemudian atur variabel menjadi
bd.Budget
:double tempVar = 0.0; if (double.TryParse(objReader[i].ToString(), out tempVar)) { bd.Budget = tempVar; }
Pembaruan : Langsung dari MSDN:
sumber
Mungkin menarik - Anda bisa menulis sendiri:
//double.TryParse(, out bd.Budget); bool result = TryParse(s, value => bd.Budget = value); } public bool TryParse(string s, Action<double> setValue) { double value; var result = double.TryParse(s, out value); if (result) setValue(value); return result; }
sumber
Ini adalah posting yang sangat lama, tetapi saya mengubah yang diterima, karena ada cara yang lebih nyaman untuk melakukan ini yang saya tidak tahu.
Ini disebut deklarasi sebaris dan mungkin selalu tersedia (seperti dalam menggunakan pernyataan) atau mungkin telah ditambahkan dengan C # 6.0 atau C # 7.0 untuk kasus seperti itu, tidak yakin, tetapi tetap berfungsi seperti pesona:
Inetad tentang ini
double temp; double.TryParse(objReader[i].ToString(), out temp); bd.Budget = temp;
Gunakan ini:
double.TryParse(objReader[i].ToString(), out double temp); bd.Budget = temp;
sumber
Jadi Anggaran adalah properti, bukan?
Pertama-tama, setel ke variabel lokal, lalu setel nilai properti ke variabel tersebut.
double t = 0; double.TryParse(objReader[i].ToString(), out t); bd.Budget = t;
sumber
Biasanya ketika saya mencoba melakukan ini, itu karena saya ingin menyetel properti saya atau membiarkannya pada nilai default. Dengan bantuan jawaban dan
dynamic
tipe ini kita dapat dengan mudah membuat metode ekstensi string agar tetap satu baris dan sederhana.public static dynamic ParseAny(this string text, Type type) { var converter = TypeDescriptor.GetConverter(type); if (converter != null && converter.IsValid(text)) return converter.ConvertFromString(text); else return Activator.CreateInstance(type); }
Gunakan seperti itu;
bd.Budget = objReader[i].ToString().ParseAny(typeof(double)); // Examples int intTest = "1234".ParseAny(typeof(int)); // Result: 1234 double doubleTest = "12.34".ParseAny(typeof(double)); // Result: 12.34 decimal pass = "12.34".ParseAny(typeof(decimal)); // Result: 12.34 decimal fail = "abc".ParseAny(typeof(decimal)); // Result: 0 string nullStr = null; decimal failedNull = nullStr.ParseAny(typeof(decimal)); // Result: 0
Pilihan
Di samping catatan, jika itu adalah
SQLDataReader
Anda juga dapat menggunakanGetSafeString
ekstensi untuk menghindari pengecualian nol dari pembaca.public static string GetSafeString(this SqlDataReader reader, int colIndex) { if (!reader.IsDBNull(colIndex)) return reader.GetString(colIndex); return string.Empty; } public static string GetSafeString(this SqlDataReader reader, string colName) { int colIndex = reader.GetOrdinal(colName); if (!reader.IsDBNull(colIndex)) return reader.GetString(colIndex); return string.Empty; }
Gunakan seperti itu;
bd.Budget = objReader.GetSafeString(i).ParseAny(typeof(double)); bd.Budget = objReader.GetSafeString("ColumnName").ParseAny(typeof(double));
sumber