Virtual jadvaldan qanday qutulish mumkin? Yopilgan sinf

Bilib olganimdek, yopiq kodini yaratish VTable-ga qarash yoki men noto'g'ri ekansiz? Agar sinfni sealed qilsam, bu sinf hiyerarşisindeki barcha virtual usullar ham sealed bilan belgilanadi degan ma'noni anglatadimi?

Misol uchun:

public class A {
    protected virtual void M() { ........ }
    protected virtual void O() { ........ }
}

public sealed class B : A {
   //I guess I can make this private for sealed class
    private override void M() { ........ }
   //Is this method automatically sealed? In the meaning that it doesn't have to look in VTable and can be called directly?

   //Also what about O() can it be called directly too, without VTable?
}
9
Yo'q, usul chaqiruvi hali ham virtual bo'ladi.
qo'shib qo'ydi muallif InBetween, manba
Yo'q, usul chaqiruvi hali ham virtual bo'ladi.
qo'shib qo'ydi muallif InBetween, manba
@Not Yopiq usulni belgilash hech qanday ta'siri yo'q, qo'ng'iroq hali ham virtual bo'ladi
qo'shib qo'ydi muallif InBetween, manba
@Not Yopiq usulni belgilash hech qanday ta'siri yo'q, qo'ng'iroq hali ham virtual bo'ladi
qo'shib qo'ydi muallif InBetween, manba
Siz deyarli to'g'ri deb hisoblaysiz - bu usuli sinfni emas, balki sealed deb belgilashingiz kerak.
qo'shib qo'ydi muallif Nat, manba
@InBayt siz haqsiz, men savolni noto'g'ri tushunaman.
qo'shib qo'ydi muallif Nat, manba
@InBayt siz haqsiz, men savolni noto'g'ri tushunaman.
qo'shib qo'ydi muallif Nat, manba
@Menimcha, men quyida izoh berdim - bu maqolada, sinfning muhri bosilgan bo'lishi mumkin: codebetter.com/patricksmacchia/2008/01/05/… Men uchun har bir virtual usuli emas, balki muhrlangan sinfni belgilash men uchun osonroqdir.
qo'shib qo'ydi muallif Candid Moon, manba
@Menimcha, men quyida izoh berdim - bu maqolada, sinfning muhri bosilgan bo'lishi mumkin: codebetter.com/patricksmacchia/2008/01/05/… Men uchun har bir virtual usuli emas, balki muhrlangan sinfni belgilash men uchun osonroqdir.
qo'shib qo'ydi muallif Candid Moon, manba

8 javoblar

Shuni ta'kidlash kerakki, C#, odatda virtual bo'lmagan usulda ham, mos yozuvlar turidagi har qanday misol usuliga virtual qo'ng'iroqlarni amalga oshiradi. Buning sababi, C# qoida mavjud emas, chunki null murojaat uchun usulni chaqirish noqonuniy hisoblanadi .NET qoidasidir (agar null mos yozuvlar uslubini chaqirsangiz va u usul o'z-o'zidan maydonga kirsa) yoki virtual uslub, u yaxshi ishlaydi) va callvirt dan foydalanish bu qoidani amalga oshirishning arzon usuli hisoblanadi.

C # nolinchi nusxadagi murojaatlar uchun callvirt o'rniga call ni ishlab chiqaradi, ba'zi hollarda mos yozuvlar null yo'q. ?. dan boshlab, obj? .SomeMethod() yordamida null-check allaqachon sodir bo'lganligini bildiradi, agar SomeMethod() Bu virtual kod call ga yoziladi. if (obj! = Null) {obj (obj! = . . kodini tuzish kodi null-checkning bajarilganligini bilmasligi sababli .SomeMethod ();} . Tegishli mantiq juda lokallashgan .

Virtual darajalarda virtual uslubni qidirishni siljitish darajasida o'tkazish mumkin. Bu base qanday ishlaydi; callvirt o'rniga bazani amalga oshirishda call ga yozib olingan. Ba'ziMethod virtual yoki yopiq bo'lgan (har biri alohida yoki obj turi yopilganligi sababli) obj? .SomeMethod() keyinchalik bu kodni chaqiriq sifatida qabul qilishning nazariy jihatdan imkoni bo'lishi mumkin. Deklaratsiya turi bilan yopiq turdagi ierarxiyadagi sinflar sinflarni o'chirib qo'yishi yoki o'chirib yuborishi mumkin bo'lsa, yana to'g'ri ishlashiga ishonch hosil qilish uchun alohida qo'shimcha tekshirishlar kerak. Bu optimallashni xavfsiz bo'lish uchun ierarxiyani (va bilimlarning o'zgarmasligi, hozirda yig'iladigan yig'ilishda mavjud bo'lgan barcha turdagi vositalar) bir necha global bilimlarni talab qiladi. Va foyda juda kichik. Holbuki, ko'pincha shu vaqtning o'zida ko'pincha mavjud emas, chunki callvirt ko'p vaqtincha virtual bo'lmagan qo'ng'iroqlarda ham ishlatiladi.

sealed derazasining chaqiruvni qanday shakllantirayotganiga ta'sir qiladi va bu, albatta, ko'pincha unga ta'sir qilmaydi, deb o'ylamayman.

Jitter yanada ko'proq ma'lumotni qo'llashi mumkin, ammo yana farq juda kichik bo'lsa. Men bilaman, siz o'zingiz bilgan sinflaringizni sealed sifatida bekor qilmasliklarini tavsiya qilaman va jitter bulardan foydalanganda u ajoyib, lekin men tavsiya qiladigan asosiy sabab bu emas, balki to'g'riligi. Agar biror joyga sealed ni belgilagan sinfni bekor qilmoqchi bo'lsangiz, unda A ni o'zgartiring. Siz o'zingizning dizayni biroz o'zgartirdingiz va sealed (5 sekunddan keyin uni olib tashlash uchun ishlash) yoki B. siz bir joyda biror narsa qildingiz. Qayta ko'rib chiqishning qisqacha to'xtatilishi yaxshi.

Agar sinfi muhrlangan bo'lsa, bu sinf hiyerarşisindeki barcha virtual usullar ham muhrlangan bo'lishi kerak degan ma'noni anglatadimi?

Ular aniq ko'rsatilganidek, xuddi shu tarzda muhrlangan deb hisoblanadi.

2
qo'shib qo'ydi

Shuni ta'kidlash kerakki, C#, odatda virtual bo'lmagan usulda ham, mos yozuvlar turidagi har qanday misol usuliga virtual qo'ng'iroqlarni amalga oshiradi. Buning sababi, C# qoida mavjud emas, chunki null murojaat uchun usulni chaqirish noqonuniy hisoblanadi .NET qoidasidir (agar null mos yozuvlar uslubini chaqirsangiz va u usul o'z-o'zidan maydonga kirsa) yoki virtual uslub, u yaxshi ishlaydi) va callvirt dan foydalanish bu qoidani amalga oshirishning arzon usuli hisoblanadi.

C # nolinchi nusxadagi murojaatlar uchun callvirt o'rniga call ni ishlab chiqaradi, ba'zi hollarda mos yozuvlar null yo'q. ?. dan boshlab, obj? .SomeMethod() yordamida null-check allaqachon sodir bo'lganligini bildiradi, agar SomeMethod() Bu virtual kod call ga yoziladi. if (obj! = Null) {obj (obj! = . . kodini tuzish kodi null-checkning bajarilganligini bilmasligi sababli .SomeMethod ();} . Tegishli mantiq juda lokallashgan .

Virtual darajalarda virtual uslubni qidirishni siljitish darajasida o'tkazish mumkin. Bu base qanday ishlaydi; callvirt o'rniga bazani amalga oshirishda call ga yozib olingan. Ba'ziMethod virtual yoki yopiq bo'lgan (har biri alohida yoki obj turi yopilganligi sababli) obj? .SomeMethod() keyinchalik bu kodni chaqiriq sifatida qabul qilishning nazariy jihatdan imkoni bo'lishi mumkin. Deklaratsiya turi bilan yopiq turdagi ierarxiyadagi sinflar sinflarni o'chirib qo'yishi yoki o'chirib yuborishi mumkin bo'lsa, yana to'g'ri ishlashiga ishonch hosil qilish uchun alohida qo'shimcha tekshirishlar kerak. Bu optimallashni xavfsiz bo'lish uchun ierarxiyani (va bilimlarning o'zgarmasligi, hozirda yig'iladigan yig'ilishda mavjud bo'lgan barcha turdagi vositalar) bir necha global bilimlarni talab qiladi. Va foyda juda kichik. Holbuki, ko'pincha shu vaqtning o'zida ko'pincha mavjud emas, chunki callvirt ko'p vaqtincha virtual bo'lmagan qo'ng'iroqlarda ham ishlatiladi.

sealed derazasining chaqiruvni qanday shakllantirayotganiga ta'sir qiladi va bu, albatta, ko'pincha unga ta'sir qilmaydi, deb o'ylamayman.

Jitter yanada ko'proq ma'lumotni qo'llashi mumkin, ammo yana farq juda kichik bo'lsa. Men bilaman, siz o'zingiz bilgan sinflaringizni sealed sifatida bekor qilmasliklarini tavsiya qilaman va jitter bulardan foydalanganda u ajoyib, lekin men tavsiya qiladigan asosiy sabab bu emas, balki to'g'riligi. Agar biror joyga sealed ni belgilagan sinfni bekor qilmoqchi bo'lsangiz, unda A ni o'zgartiring. Siz o'zingizning dizayni biroz o'zgartirdingiz va sealed (5 sekunddan keyin uni olib tashlash uchun ishlash) yoki B. siz bir joyda biror narsa qildingiz. Qayta ko'rib chiqishning qisqacha to'xtatilishi yaxshi.

Agar sinfi muhrlangan bo'lsa, bu sinf hiyerarşisindeki barcha virtual usullar ham muhrlangan bo'lishi kerak degan ma'noni anglatadimi?

Ular aniq ko'rsatilganidek, xuddi shu tarzda muhrlangan deb hisoblanadi.

2
qo'shib qo'ydi

"Tasavvur qilamanki, men buni yopiq sinf uchun tayyorlay olaman"

Mirasa ierarxiyasida kirishni o'zgartirishni o'zgartira olmaysiz. Agar asosiy usulda usul public bo'lsa, uni private yoki internal yoki protected sinflar. Modifikatorni faqat sizning usulingizni new deb e'lon qilsangiz o'zgartirishingiz mumkin:

private new void M() { ........ }

Men bilib olganimdek, sinfning muhrlangan qismi VTable-ga murojaat qilishdan qutuladi   Men xato qilyapmanmi?

Yopiq sinfi ierarxikada oxirgi bo'ladi, chunki undan meros bo'lolmaysiz. Ushbu kod sealed sinf asosiy usuldan ba'zi usulni bekor qilgan holda, virtual jadvalni sealed sinfida ishlatish mumkin.

Agar sinfi muhrlangan qilsam, bu degani barcha virtual usullar   sinf hiyerarşisi ham muhrlangan deb belgilangan?

IL kodini ko'rishingiz mumkin:

.method family hidebysig virtual           //method is not marked as sealed
    instance void M() cil managed 
{        
    .maxstack 8

    IL_0000: nop 
    IL_0001: ret value
}  

Boshqaruv sealed deb belgilanmaydi. Ushbu usulni sealed deb aniq belgilagan bo'lsangiz ham bir xil IL kodini olasiz.

Bundan tashqari, usulni yopiq sinfida sealed sifatida belgilash uchun hech qanday sabab yo'q. Agar sinf sealed bo'lsa, uni meros qilib ololmaysiz, uning usullarini meros qilib olmaysiz.

Virtual jadvallar haqida - Agar usul o'chirib tashlansa va uni virtual jadvaldan o'chirsangiz, uni hech qachon devralma hiyerarşisindek foydalana olmaysiz, shuning uchun metodni bekor qilish va uni hech qachon meros huquqi tizimida ishlatish uchun hech qanday sabab yo'q.

2
qo'shib qo'ydi
Agar siz yopiq sinfida sealed usulini belgilasangiz, siz bir xil ILni olasiz. yopiq holda prnt.sc/eecpnk yopiq - prntscr.com/eecq2w
qo'shib qo'ydi muallif Roman Doskoch, manba
Ishlash haqida nima desa bo'ladi? Ushbu usullarni VTablega qaramaslik kerak. Bilaman, bu juda oz miqdordir va ehtimol ko'p hollarda ahamiyatga ega bo'lmaydi va muhrlangan usulni ishlab chiqarishning dizayn sababi bo'lishi kerak. Shunday qilib, VTablega qarashni to'xtatish uchun muhrlangan har bir usulni belgilashim kerakmi?
qo'shib qo'ydi muallif Candid Moon, manba
Rahmat, keyin menimcha, sinfning muhri bosilganligiga bog'liq bo'lsa, unda bu usulda ushbu usulga amal qilmaslik ehtimoli mavjud: codebetter.com/patricksmacchia/2008/01/05/…
qo'shib qo'ydi muallif Candid Moon, manba

"Tasavvur qilamanki, men buni yopiq sinf uchun tayyorlay olaman"

Mirasa ierarxiyasida kirishni o'zgartirishni o'zgartira olmaysiz. Agar asosiy usulda usul public bo'lsa, uni private yoki internal yoki protected sinflar. Modifikatorni faqat sizning usulingizni new deb e'lon qilsangiz o'zgartirishingiz mumkin:

private new void M() { ........ }

Men bilib olganimdek, sinfning muhrlangan qismi VTable-ga murojaat qilishdan qutuladi   Men xato qilyapmanmi?

Yopiq sinfi ierarxikada oxirgi bo'ladi, chunki undan meros bo'lolmaysiz. Ushbu kod sealed sinf asosiy usuldan ba'zi usulni bekor qilgan holda, virtual jadvalni sealed sinfida ishlatish mumkin.

Agar sinfi muhrlangan qilsam, bu degani barcha virtual usullar   sinf hiyerarşisi ham muhrlangan deb belgilangan?

IL kodini ko'rishingiz mumkin:

.method family hidebysig virtual           //method is not marked as sealed
    instance void M() cil managed 
{        
    .maxstack 8

    IL_0000: nop 
    IL_0001: ret value
}  

Boshqaruv sealed deb belgilanmaydi. Ushbu usulni sealed deb aniq belgilagan bo'lsangiz ham bir xil IL kodini olasiz.

Bundan tashqari, usulni yopiq sinfida sealed sifatida belgilash uchun hech qanday sabab yo'q. Agar sinf sealed bo'lsa, uni meros qilib ololmaysiz, uning usullarini meros qilib olmaysiz.

Virtual jadvallar haqida - Agar usul o'chirib tashlansa va uni virtual jadvaldan o'chirsangiz, uni hech qachon devralma hiyerarşisindek foydalana olmaysiz, shuning uchun metodni bekor qilish va uni hech qachon meros huquqi tizimida ishlatish uchun hech qanday sabab yo'q.

2
qo'shib qo'ydi
Agar siz yopiq sinfida sealed usulini belgilasangiz, siz bir xil ILni olasiz. yopiq holda prnt.sc/eecpnk yopiq - prntscr.com/eecq2w
qo'shib qo'ydi muallif Roman Doskoch, manba
Ishlash haqida nima desa bo'ladi? Ushbu usullarni VTablega qaramaslik kerak. Bilaman, bu juda oz miqdordir va ehtimol ko'p hollarda ahamiyatga ega bo'lmaydi va muhrlangan usulni ishlab chiqarishning dizayn sababi bo'lishi kerak. Shunday qilib, VTablega qarashni to'xtatish uchun muhrlangan har bir usulni belgilashim kerakmi?
qo'shib qo'ydi muallif Candid Moon, manba
Rahmat, keyin menimcha, sinfning muhri bosilganligiga bog'liq bo'lsa, unda bu usulda ushbu usulga amal qilmaslik ehtimoli mavjud: codebetter.com/patricksmacchia/2008/01/05/…
qo'shib qo'ydi muallif Candid Moon, manba

Sinf yoki usulni muhrlangan qilish hech qanday ta'sirga ega bo'lmasa, B.M() ga biron-bir chaqiriq virtual bo'ladi.

Buning nima sababli o'ynashiga qaramasdan, M() kodi A da e'lon qilinganligi sababli, uni "tegishli" deb bo'lmaydi B .

Agar yaratilgan kodning IL kodini tekshirsangiz, tegishli buyruq callvirt misol string nom maydoni .. :: M() ekanligini va shuning uchun < kodi> B yopilgan bo'lsa, qo'ng'iroq virtual bo'lishi kerak.

0
qo'shib qo'ydi

Sinf yoki usulni muhrlangan qilish hech qanday ta'sirga ega bo'lmasa, B.M() ga biron-bir chaqiriq virtual bo'ladi.

Buning nima sababli o'ynashiga qaramasdan, M() kodi A da e'lon qilinganligi sababli, uni "tegishli" deb bo'lmaydi B .

Agar yaratilgan kodning IL kodini tekshirsangiz, tegishli buyruq callvirt misol string nom maydoni .. :: M() ekanligini va shuning uchun < kodi> B yopilgan bo'lsa, qo'ng'iroq virtual bo'lishi kerak.

0
qo'shib qo'ydi

Muhrlangan, siz undan meros qilib olmaysiz yoki uni bekor qilolmaysiz. Agar siz B sinfidan meros qilib ololmasangiz, M. usulni bekor qilishning hech qanday usuli yo'q. Men qo'ng'iroqni qabul qilmayman, deb o'ylayman. Sizning namunangizda qo'ng'iroq usulida u A sinfidagi usulni qidirish va uni chaqirish kerak bo'ladi. Bu vtable orqali sodir bo'ladi.

0
qo'shib qo'ydi

Muhrlangan, siz undan meros qilib olmaysiz yoki uni bekor qilolmaysiz. Agar siz B sinfidan meros qilib ololmasangiz, M. usulni bekor qilishning hech qanday usuli yo'q. Men qo'ng'iroqni qabul qilmayman, deb o'ylayman. Sizning namunangizda qo'ng'iroq usulida u A sinfidagi usulni qidirish va uni chaqirish kerak bo'ladi. Bu vtable orqali sodir bo'ladi.

0
qo'shib qo'ydi