objek nullable harus memiliki nilai

190

Ada paradoks dalam deskripsi pengecualian: Objek nullable harus memiliki nilai (?!)

Ini masalahnya:

Saya punya DateTimeExtendedkelas, ya sudah

{
  DateTime? MyDataTime;
  int? otherdata;

}

dan seorang konstruktor

DateTimeExtended(DateTimeExtended myNewDT)
{
   this.MyDateTime = myNewDT.MyDateTime.Value;
   this.otherdata = myNewDT.otherdata;
}

menjalankan kode ini

DateTimeExtended res = new DateTimeExtended(oldDTE);

melempar InvalidOperationExceptiondengan pesan:

Objek nullable harus memiliki nilai.

myNewDT.MyDateTime.Value- valid dan mengandung DateTimeobjek biasa .

Apa arti dari pesan ini dan apa yang saya lakukan salah?

Perhatikan oldDTEtidak null. Saya telah menghapus Valuedari myNewDT.MyDateTimetetapi pengecualian yang sama dilempar karena setter yang dihasilkan.

Dani
sumber
Apa konstruktor lainnya?
Paul Creasey
Aneh. Saya mereproduksi pengecualian dengan .Nilai di sana, dan tidak ada pengecualian tanpa .Nilai di sana. Anda yakin menjalankan kode yang diperbarui?
Yuliy
Konstruktor mengambil contoh dari dirinya sendiri. bagaimana Anda membuat instance pertama itu?
Paul Creasey
itu dibangun sebagai baru () tanpa parameter, dan kemudian saya menambahkan nilai-nilai (berfungsi).
Dani
6
Masalah terpecahkan - masalahnya tidak ada ... ada setter yang dihasilkan ke data lain dan MyDateTime, yang memeriksa nilai sebelum menyetelnya .. terbang saat itu nol !!!
Dani

Jawaban:

201

Anda harus mengubah jalur this.MyDateTime = myNewDT.MyDateTime.Value;menjadi adilthis.MyDateTime = myNewDT.MyDateTime;

Pengecualian yang Anda terima dilemparkan ke dalam .Valueproperti Nullable DateTime , karena diharuskan untuk mengembalikan a DateTime(karena itulah kontrak untuk .Valuenegara bagian), tetapi tidak dapat melakukannya karena tidak ada DateTimeuntuk kembali, sehingga mengeluarkan pengecualian.

Secara umum, itu adalah ide yang buruk untuk secara membabi buta memanggil .Valuetipe nullable, kecuali Anda memiliki pengetahuan sebelumnya bahwa variabel itu HARUS mengandung nilai (yaitu melalui .HasValuecek).

EDIT

Berikut kode untuk DateTimeExtendeditu tidak membuang pengecualian:

class DateTimeExtended
{
    public DateTime? MyDateTime;
    public int? otherdata;

    public DateTimeExtended() { }

    public DateTimeExtended(DateTimeExtended other)
    {
        this.MyDateTime = other.MyDateTime;
        this.otherdata = other.otherdata;
    }
}

Saya mengujinya seperti ini:

DateTimeExtended dt1 = new DateTimeExtended();
DateTimeExtended dt2 = new DateTimeExtended(dt1);

Menambahkan .Valuepada other.MyDateTimemenyebabkan pengecualian. Menghapusnya menghilangkan pengecualian. Saya pikir Anda mencari di tempat yang salah.

Yuliy
sumber
Anda benar tentang nilai., Namun sesuatu yang lain menyebabkan pengecualian. Saya telah menghapus nilai., Dan saya telah mengubah urutan kode konstruktor-menyalin nilai int terlebih dahulu, tetapi pengecualian yang sama dilemparkan.
Dani
Saya telah mengomentari pertanyaan - menemukan masalah, itu dalam setter yang dihasilkan untuk properti.
Dani
ya, ini menyelesaikan masalah saya, saya hanya mengubah objek null dapat menjadi non null mampu, dan mengkonversi datetime ke string secara langsung, bukan dengan datetimeobject.value.datetime.tostring ()
adnan
Jawaban yang bagus Mendapatkan pengecualian memanggil .Valueobjek null masuk akal (saya kira), tetapi pesan pengecualian benar-benar menyesatkan jika Anda berhadapan dengan dua objek Nullable. Sesuatu seperti 'Properti .Value membutuhkan objek yang bukan nol' akan lebih masuk akal.
DVK
9

Saat menggunakan metode ekstensi LINQ (misalnya Select, Where), fungsi lambda mungkin dikonversi ke SQL yang mungkin tidak berperilaku identik dengan kode C # Anda. Sebagai contoh, hubung singkat C # dievaluasi &&dan ||dikonversi ke SQL ANDdan OR. Ini dapat menyebabkan masalah saat Anda memeriksa null di lambda Anda.

Contoh:

MyEnum? type = null;
Entities.Table.Where(a => type == null || 
    a.type == (int)type).ToArray();  // Exception: Nullable object must have a value
Pelindung satu
sumber
5
Saya menyadari jawaban ini tidak relevan dengan kasus spesifik OP, tetapi relevan dengan Pengecualian yang didapatnya. Juga, halaman ini adalah hit pertama di Google untuk pengecualian itu, yang membuatnya relevan.
Pelindung satu
6

Coba jatuhkan .value

DateTimeExtended(DateTimeExtended myNewDT)
{
   this.MyDateTime = myNewDT.MyDateTime;
   this.otherdata = myNewDT.otherdata;
}
Paul Creasey
sumber
tidak membantu. itu melempar pengecualian yang sama jika saya menjalankan baris ke-2 terlebih dahulu.
Dani
2

Dalam hal ini oldDTE adalah null, jadi ketika Anda mencoba mengakses oldDTE.Value InvalidOperationException dilempar karena tidak ada nilai. Dalam contoh Anda, Anda dapat melakukannya:

this.MyDateTime = newDT.MyDateTime;
Lee
sumber
The oldDTE tidak null, tapi saya dihapus nilai bagaimanapun ... itu masih melemparkan pengecualian bahwa ....
Dani
1

Tetapkan anggota secara langsung tanpa .Valuebagian:

DateTimeExtended(DateTimeExtended myNewDT)
{
   this.MyDateTime = myNewDT.MyDateTime;
   this.otherdata = myNewDT.otherdata;
}
Cecil Memiliki Nama
sumber
0

Sepertinya oldDTE.MyDateTime adalah nol, jadi konstruktor mencoba mengambil nilainya - yang dilemparkan.

Pavel Radzivilovsky
sumber
0

Saya mendapat pesan ini ketika mencoba mengakses nilai-nilai objek bernilai nol.

sName = myObj.Name;

ini akan menghasilkan kesalahan. Pertama, Anda harus memeriksa apakah objek tidak null

if(myObj != null)
  sName = myObj.Name;

Ini bekerja.

Juris
sumber
1
Sebelum menjawab, cobalah membaca jawaban lain untuk pertanyaan terlebih dahulu - terutama jawaban yang diterima yang menyatakan dengan tepat apa yang Anda tempatkan dalam jawaban Anda . Meskipun tidak menunjukkannya menggunakan kode, itu menjabarkannya. Juga, cobalah membuat contoh kode Anda relevan dengan pertanyaan - seperti this.MyDateTime = myNewDT.MyDateTime.Value;, bukansName = myObj.Name;
furnitur baru
0

Saya mendapat solusi ini dan itu berfungsi untuk saya

if (myNewDT.MyDateTime == null)
{
   myNewDT.MyDateTime = DateTime.Now();
}
KKG
sumber