Nimaga qutulish C # da ochiq kastingni talab qiladi?

Boks - qiymat turini yopiq bo'lgan boshqariladigan kichkina ob'ektga aylantirish jarayoni. Unboxing - bu derleyici uchun aniq translatsiyani talab qiladigan teskari jarayon. Boks ma'lumot turini saqlab turgandan buyon, nima uchun ochiq kastingni so'ramasdan, uni ishlatishni to'xtata olmaysizmi?

class BoxUnBox
{
 static void Main()
 {
   int i = 123;     //a value type
   object o = i;    //boxing
   int j = (int)o;  //unboxing - Why is an explicit cast required?
 }
}
18
- bilan birgalikda ishlatilmaydigan qiymat turi bo'lganligi uchun o . Biroq o ni int sifatida ishlatishingiz mumkin .
qo'shib qo'ydi muallif HimBromBeere, manba
@ErikLippert: Eh, men uni sotib olmadim. C#, bu osonlikcha mahalliy turlar uchun hech qanday qo'shimcha xarajatlarga ega bo'lmasdan qo'llab-quvvatlagan bo'lishi mumkin ... masalan. x86-ga faqat kutilgan qiymati uzoq vaqt sifatida saqlab qo'yish kerak va unda qutiga kutish vaqti kelganida siz faqat o'zgarmaydiganga kerak bo'lgan ko'p baytni nusxalashingiz mumkin. Agar siz tekshiruvni amalga oshirsangiz, faqat typecode1 <= typecode2 ga to'g'ri kelishi mumkin edi.
qo'shib qo'ydi muallif Mehrdad, manba
Ehtimol, uning xavfli bo'lishi mumkinmi? ob'ekt da saqlangan narsangiz bo'lishi mumkin
qo'shib qo'ydi muallif Sergey Berezovskiy, manba
Undan qutulishning hech qanday aloqasi yo'q, pastga tushish har doim ochiq-oydin tashlanishni talab qiladi. Bu talabga javob beradi, shuning uchun derleyici nima qilayotganingizni bilishingizga to'g'ri keladi. Faqat i o'zgaruvchisini long deb e'lon qiling, shunda u havoga uchib ketadi. Endi uni to'g'ri bajaring, int j = Convert.ToInt32 (o);
qo'shib qo'ydi muallif Hans Passant, manba
Kutish turi ish vaqtida ma'lum bo'lsa-da, kompilyatsiya vaqtida noma'lum. Shunday qilib, derazadan qutilishni kutayotgan narsalarni derazaga aytishga to'g'ri keladi.
qo'shib qo'ydi muallif Erno de Weerd, manba
Sizning keyingi savolingiz "OK, nima uchun unboxing translyatsiyasi kutilgan obyektning aniq turini bo'lishi kerak?" Boshqacha qilib aytganda, uzoq vaqt davomida int uzamoqchi bo'lsam, nima uchun uzoq kutib turishim bilan qutiga ichki qutichani ocholmayman? bu savolni bir muncha vaqt o'ylab ko'ring va ericlippert.com/2009/03/03/representation-and-identity
qo'shib qo'ydi muallif Eric Lippert, manba
@HimBromBeere yaxshi ta'qib qilish, doimo yangi narsalarni o'rganish. faqat hozir men uchun turli xil sintaksisi tushuntirilgan. Men bu jamoatni yaxshi ko'raman.
qo'shib qo'ydi muallif downrep_nation, manba
"U int kabi" haqida qanday fikrdasiz? Men uning hali aniq ekanligini bilaman, lekin tez-tez dumaloqlardan ko'ra yaxshi
qo'shib qo'ydi muallif downrep_nation, manba

7 javoblar

Sizning savolingiz faqat qutqarish operatsiyalari bilan bog'liq emas. Aslida u "Nima uchun aniq aylantirishni ishlatishim kerak?" Deb aytiladi. Quyidagi misolni ko'rib chiqing:

int i = 123;
long l = i;
int j = (int)l;//OMG why??

Javob oddiy va siz buni C# spetsifikatsiyasida topishingiz mumkin 6.2 aniq aylanmalar :

aniq konvertatsiya qilish - bu tomonidan tasdiqlanmagan translatsiyalar   har doim muvaffaqiyatli , ma'lum bo'lgan konvertatsiya ehtimol yo'qoladi   ma'lumotlar va turli domen turlari bo'yicha konvertatsiya qilish etarli   

Yuqoridagi misolda long int oralig'iga mos kelmaydigan qiymatlarni saqlashi mumkin, chunki ma'lumotni yo'qotishingiz mumkin . Lekin int funktsiyasini long ga belgilashda hech qachon ma'lumotni yo'qotmaysiz:

long l = i;//safe

Sizning namunangizda aniq konvertatsiya qilish kerak, chunki yopiq konvertatsiya har doim muvaffaqiyatga erishish uchun isbotlanmaydi . ob'ekt turidagi o'zgaruvchilar murojaat qilishlari mumkin  har qanday turdagi. String haqida nima desa bo'ladi?

object o = i; //implicit and always safe
o = "Now I have a machinegun ho-ho-ho";//safe too
int j = o;    //will not succeed if o is string

Analogiya

Ob'ektiv o'zgaruvchi - qora qutiga o'xshash - musiqa CD, qalam, telefon yoki banan. Siz nafaqat siz, balki har bir kishi u erda biron narsani qo'yishadi. Agar siz ertalab qora qutiga tushirgan so'nggi narsa banan bo'lsa, kechqurun qaytib kelib, qora qutidan chiqarib olgan narsangizni eb olasizmi? Agar siz yolg'iz yashasangiz va xona yopiq bo'lsa va sizning xotirangiz ajoyib va ​​... Va siz nima uchun hamma ularning qutisini mazmunini ovqatdan oldin tekshiradi. Agar siz yolg'iz yashamasangiz yoki xona yopilmasa yoki telefonni qutiga kiritganingizdan so'nggina unutishingiz mumkin ... Bon appetite

42
qo'shib qo'ydi
Juda yaxshi o'xshashlik! Fikrni tushuntirishning eng yaxshi usuli
qo'shib qo'ydi muallif Prokurors, manba
long dan int ga o'tish ikki jihatdan aniqlik mezonlariga javob beradi: tekshirilmagan kontekstda siz ma'lumotni yo'qotishingiz mumkin; tasdiqlangan kontekstda, aylantirish muvaffaqiyatsiz bo'lishi mumkin OverflowException . (Dasturchilar odatda C# -ni arifmetik tekshirganligini unutishadi va, aslida u asl qiymati emas.)
qo'shib qo'ydi muallif Jeroen Mostert, manba

Agar "Salom Dunyo" deb aytish uchun kimdir o tarkibini o'zgartirsa nima bo'ladi. Siz nima qilayotganingizni bilishingizga ishonch hosil qilish uchun, kompilyator sizdan kutilgan qiymati aniq tashlashni talab qiladi.

Asosan, yopiq konvertatsiya qilish narsa obyektining har qanday namunasi o , shuningdek, aniq ko'rinmaydigan int misoli sifatida ifodalanishi mumkinligini bildiradi. Buni misol qilib olaylik:

int i = -1;
long j = i;

Agar tamsayı bo'lgan i o'zgaruvchisi ham long deb hisoblanishi mumkin. Shu sababli aniq to'qima bu erda aniq. Boshqa tomondan, har uzun da har qanday ma'lumot yo'qotilishi holda int ga aylanadi. Shunday qilib, aniqlash uchun aniq bir shtatga kerak: bilsam, mumkin ba'zi ma'lumotlarni yo'qotish bo'lishi mumkin, lekin men bunga umuman ahamiyat bermayapman.

6
qo'shib qo'ydi

Agar Int32 ob'ekti bo'lsa, ob'ekt </> Int32 . Derleyici birinchi holatda nima qilish kerakligini biladi, lekin ikkinchi holatda nima qilayotganingizni bilish uchun derleyiciga aytish kerak va unboxingni bajarish mumkinligini kafolatlashingiz kerak.

Meros munosabat yo'nalishdir! Ota-ona farzanddan farq qiladi.

5
qo'shib qo'ydi
Yo'q, Int32 - bu qiymat turi va shuning uchun ob'ekt emas. Biroq aylana ni ob'ekt * ga o'zgartirishi mumkin, boks nima degani.
qo'shib qo'ydi muallif HimBromBeere, manba
@JeroenMostert Void - bu tip, chunki u tip sifatida belgilanadi. Void bir ob'ekt emas, balki , chunki xususiyatlari ham juda ko'p. atrofidagi haqiqiy dasturning tafsilotlari o'zgarmasligi mumkin. Bu tushuntirishlar haqiqatdir, chunki ular aniqlangan .
qo'shib qo'ydi muallif Servy, manba
Texnik ravishda hamma narsa ob'ektidan egalik qilmaydi. Ko'rsatkichlar ob'ekt dan meros bo'lmaydilar, yoki Void .
qo'shib qo'ydi muallif Servy, manba
Int32 uchun boshqa nom kiradi: texnik jihatdan noto'g'ri: int C# da System.Int32 , ya'ni. NET "maxsus" struct ... jumlaning qolgan qismi OK.
qo'shib qo'ydi muallif xanatos, manba
@ A.Chiesa Bu to'g'ri va noto'g'ri ... Nima uchun texnika jihatidan ob'ektdan meros bo'lib qolsa, qiymat turlarida meros "g'alati"
qo'shib qo'ydi muallif xanatos, manba
@Servy: C# va CLI spesifikatsiyasini sinchkovlik bilan o'rganganman. Muammoni sizdan ko'ra nozikroq ekaniga amin bo'laman, shuningdek, moot va albatta albatta </​​i> tortishuvni davom ettirish mavzusiga juda yaqin. Void (va void ) haqida juda ko'p narsalar mavjud. Bu ko'rsatkichlar deyarli bir xil emas. Ko'rsatkichlar ishi ancha soddadir (va amaliy oqibatlarga ega).
qo'shib qo'ydi muallif Jeroen Mostert, manba
@Servy: bu texnik - Void ni olishni istasangiz, faqatgina System.Reflection asbobi. Int32 , xuddi shunday tarzda "imtiyozli tuzilish" dir. Hech narsa qaytara olmaydigan usullar/funktsiyalar aslida Void ni qaytarmasligi. Void , ValueType dan egalik qiladi, bu esa, albatta, Object dan egalik qiladi.
qo'shib qo'ydi muallif Jeroen Mostert, manba
@ A.Chiesa: C# spec kodini System.Void sifatida belgilaydigan typeof (void) kodini belgilaydi va keyinchalik "usulning qaytishi agar u qiymatni qaytarmasa void bo'lsa, u holda uni yopiq tarzda (yoki hech bo'lmasa qaytarish turi ) amalga oshiradi. CLI spektrlari masalada juda nozikroq, lekin C# da, void - bu tip. Ish. ( void kodi qaytariluvchi deb e'lon qilingan usullar qiymatni qaytarib bermaydi va, odatda, Void misollarini qaytarmaydilar, chunki hech qanday qiymat hech qachon Void .) Shuningdek qarang.
qo'shib qo'ydi muallif Jeroen Mostert, manba
Int32 , int uchun boshqa nomdir va shuning uchun ob'ekt emas, albatta, noto'g'ri.
qo'shib qo'ydi muallif A. Chiesa, manba
@Servy - siz bo'shlik turi deb aniqlangan deb hisoblaysizmi? Texnikani qidirishda ushbu ta'rifni topa olmayapman. Men juda qiziqaman;)
qo'shib qo'ydi muallif A. Chiesa, manba
@xonatos: Siz haqsiz. Amalga oshirishni amalga oshirish uchun yuqori darajada optimallashtirilgan ba'zi ogohlantirishlar mavjud. Programmers nuqtai nazaridan, odatda Int32ni tuzilgan deb hisoblash foydali bo'ladi va struct ba'zi xotira boshqaruvi farqlari bo'lgan sinfdir. Ushbu jumla qat'iy IMO.
qo'shib qo'ydi muallif A. Chiesa, manba
Bu Java emas, C #. Ob'ektlardan, hatto ibtidoiy turlardan hammasi meros bo'lib o'tadi. stackoverflow.com/a/33247833/1395758 manziliga qarang.
qo'shib qo'ydi muallif A. Chiesa, manba

Har qanday int bir ob'ektga aylanadi. Barcha ob'ektlar intsga o'tkazilishi mumkin emas.

4
qo'shib qo'ydi

Derleyici sizning ob'ektingizdagi narsalarni kafolatlamaydi. Shuning uchun siz kutgan qadriyat sifatida aniq ifodalash kerak. Derleyici uchun:

Bu xavfli

object o = 45;
int j = (int)o;

shuning uchun:

object o = "something";
int j = (int)o;

Va bu derleme vaqtida ruxsat berilmaydi.

3
qo'shib qo'ydi

Translatsiya sizning ob'ektingiz nimaga ega ekanligiga qarab ishlash muddatida bajarilmasligi mumkin. Yopiq kutish mumkin bo'lganda, siz xatolardan qochishingiz mumkin, chunki siz boshqacha tarzda yozilgan narsalarni yozgan bo'lishingiz mumkin (yoki siz yoki siz boshqalarning kodini noto'g'ri tushungansiz). Derivat siz aniq yozib chiqarishni talab qiladi, chunki siz ushbu translatsiyani albatta xohlaysiz. . Aks holda, noto'g'ri aralashtirilgan kodlarni ishlab chiqaradigan turlarni aralashtirishingiz mumkin. Aniqlashni majbur qilgan holda, siz to'g'ri ish qilayotgan bo'lsangiz, ikki marta o'ylashingiz kerak.

2
qo'shib qo'ydi

Dynamic-dan foydalanish quyqa turishini oldini oladi

Aytilgan narsalardan chetga chiqmaslik kerak, lekin men texnik jihatdan undagi qutichani bajarish uchun har doim ham talab etilmasligini ta'kidlashni istardim. Dinamik kalit so'z sistemaga unlocking va ishlashni automagically bajarishga imkon beradi. Men dinni ishlatishni tavsiya qilmayman, xohlamayman, faqat uning xatti-harakatiga ishora qilaman.

static void DynamicTest()
{
    int i = 123;     //a value type
    object o = i;    //boxing
    dynamic d = o;   //shift to dynamic
    int j = d;       //unboxing - No cast required
}

Edit: Jeroen Mostert wisely points out that the dynamic keyword is not any kind of magic that always makes this work. It merely defers evaluation to a runtime behavior. So, while the above example will always work, more complex examples will definitely fail. Therefore, one must take care when using the dynamic keyword and expect (try/catch) runtime failures. The dynamic keyword can, none-the-less be a very powerful tool, if used judiciously.

1
qo'shib qo'ydi
Shuni aytish kerakki, dynamic har doim ham ishlashga mos keladigan ishlashni tekshiradi. Bu uning harakati; bu sehrli konvertatsiya tizimi emas. (Ayniqsa, agar long i = 123 ning yuqorisidagi qismda kod ishlatilsa, kod yaxshi ishlaydi, lekin ish vaqtida bajarilmaydi, chunki long dan int .)
qo'shib qo'ydi muallif Jeroen Mostert, manba