1629295403-b876e2087bddebea4bc9666fb2377a02 (846199), страница 51
Текст из файла (страница 51)
Вы у ж е в с т р е ч а л и с ь с э т и м в одном изп р и м е р о в . S o m e F u n c t i o n ( ) м о ж е т п е р е д а т ь о б ъ е к т S a v i n g s A c c o u n t методу, к о т орый ожидает объект B a n k A c c o u n t .Это преобразование можно сделать явным следующим образом:BankAccountЬа,SavingsAccountsa270=newSavingsAccount();Часть IV. Объектно-ориентированное программистba = s a ;ba =(BankAccount)sa;sa = b a ;sa =(SavingsAccount)ba;//Верно:// Н е я в н о е п р е о б р а з о в а н и е к//базовому классу разрешено// Но я в н о е п р е о б р а з о в а н и е//предпочтительнее//Ошибка://////Неявное преобразованиеподклассу запрещеноДопустимокВ первой с т р о к е о б ъ е к т S a v i n g s A c c o u n t с о х р а н я е т с я в п е р е м е н н о й т и п а B a n k A c count.
С # в ы п о л н я е т н е о б х о д и м о е п р е о б р а з о в а н и е з а в а с . В о в т о р о й с т р о к е я в н ы м образом и с п о л ь з о в а н о п е р а т о р п р и в е д е н и я т и п а .Последние две с т р о к и п р е о б р а з у ю т объект т и п а B a n k A c c o u n t в S a v i n g s A c c o u n t .О т н о ш е н и е Я В Л Я Е Т С Я н е р е ф л е к с и в н о .
Т о есть, н е с м о т р я н а т о что " З а п о р о ж е ц "является автомобилем, автомобиль — не обязательно " З а п о р о ж е ц " . Аналогично,B a n k A c c o u n t — н е о б я з а т е л ь н о S a v i n g s A c c o u n t , т а к ч т о н е я в н о е преобразование в этом направлении запрещено. Последняя строка разрешена, посколькув н е й п р о г р а м м и с т я в н о у к а з ы в а е т , ч т о он б е р е т на с е б я о т в е т с т в е н н о с т ь за выполнение данного преобразования.Неверное преобразование времени выполненияВ общем случае приведение объекта от типа B a n k A c c o u n tк типуSavingsAccount — достаточно опасная операция.
Р а с с м о т р и м с л е д у ю щ и й п р и м е р :publics t a t i cvoidProcessAmount(BankAccountbankAccount){// Вносим на с ч е т большую суммуbankAccount.Deposit(10000.00М);// Если объект — S a v i n g s A c c o u n t ,добавляемSavingsAccountSavingsAccount=(SavingsAccount)bankAccount;SavingsAccount.Accumulatelnterest();проценты{publics t a t i cvoidTestCastO{SavingsAccountsa=new S a v i n g s A c c o u n t ( ) ;ProcessAmount(sa);BankAccount ba = new B a n k A c c o u n t ( ) ;ProcessAmount(ba);}Функция P r o c e s s A c c o u n t ( )тода A c c u m u l a t e l n t e r e s t ( ) .в ы п о л н я е т н е с к о л ь к о о п е р а ц и й , в к л ю ч а я в ы з о в меПриведение baк типу S a v i n g s A c c o u n tнеобходимо, п о с к о л ь к у b a о б ъ я в л е н о к а к B a n k A c c o u n t .
П р о г р а м м а к о р р е к т н о к о м п и л и р у е т с я ,так как в с е п р е о б р а з о в а н и я т и п о в в ы п о л н е н ы я в н о .Все н о р м а л ь н о р а б о т а е т п р и п е р в о м в ы з о в е P r o c e s s A c c o u n t ( )ект S a v i n g s A c c o u n tи з T e s t ( ) . Объпередается методу P r o c e s s A c c o u n t ( ) . Преобразование типаи з B a n k A c c o u n t в S a v i n g s A c c o u n t н е в ы з ы в а е т п р о б л е м , п о с к о л ь к у о б ъ е к т b a изначально б ы л о б ъ е к т о м т и п а S a v i n g s A c c o u n t .Глава 12.
Наследование271Однако со вторым вызовом P r o c e s s A c c o u n t ()н е в с е т а к г л а д к о . Преобразованк т и п у S a v i n g s A c c o u n t н е м о ж е т б ы т ь р а з р е ш е н о . О б ъ е к т b a н е и м е е т метода Асаm u l a t e l n t e r e s t ().Н е к о р р е к т н о е п р е о б р а з о в а н и е т и п о в г е н е р и р у е т о ш и б к у в п р о ц е с с е выполнияпрограммы(такназываемуюошибкувременивыполнения(run-time errorО ш и б к и в р е м е н и в ы п о л н е н и я г о р а з д о с л о ж н е е н а й т и и и с п р а в и т ь , чем ошибкив р е м е н и к о м п и л я ц и и .
Ч т о е щ е б о л е е н е п р и я т н о , т а к а я о ш и б к а м о ж е т произоти не с в а м и , а с д р у г и м п о л ь з о в а т е л е м п р о г р а м м ы . О б ы ч н о о с о б о г о восторгау пользователей такие о ш и б к и не вызывают.Ключевые слова is и asФ у н к ц и я P r o c e s s A c c o u n t () р а б о т а л а бы к о р р е к т н о , е с л и бы м о г л а убедиться, чтоп е р е д а н н ы й е й о б ъ е к т д е й с т в и т е л ь н о и м е е т т и п S a v i n g s A c c o u n t , п е р е д т е м , как в ыподнять п р е о б р а з о в а н и е . С# предоставляет для этого два к л ю ч е в ы х слова — is и as.Использование оператора isО п е р а т о р i s п о л у ч а е т о б ъ е к т в к а ч е с т в е л е в о г о а р г у м е н т а и т и п — в к а ч е с т в е правог о .
О п е р а т о р в о з в р а щ а е т з н а ч е н и е t r u e , е с л и т и п в р е м е н и в ы п о л н е н и я объекта с л е в ас о в м е с т и м с т и п о м с п р а в а . Э т о т о п е р а т о р м о ж н о и с п о л ь з о в а т ь д л я п р о в е р к и корректности преобразования перед его в ы п о л н е н и е м .Предыдущий пример можно модифицировать с применением оператора i s , что позволит избежать ошибки времени выполнения.publics t a t i cvoidProcessAmount(BankAccountbankAccount){//ВносимнасчетбольшуюсуммуbankAccount.Deposit(10000.00М);//Еслиifобъект—(bankAccountSavingsAccount...isSavingsAccount){//...//гарантированнодобавляемSavingsAccountпроценты(преобразованиетиповработает)SavingsAccount=(SavingsAccount)bankAccount;SavingsAccount.Accumulatelnterest();}//В//Однакопротивном//Возможно,случаепочемуэтопреобразованиеBankAccountкакая-то—ненето,ошибочнаявыполняется.чтовыожидали?ситуация?}publics t a t i cvoidTestCastO{SavingsAccountsa=newSavingsAccount();ProcessAmount(sa);BankAccountba=newBankAccount();ProcessAmount(ba);}Д о б а в л е н и е о п е р а т о р а i s д а е т г а р а н т и ю , ч т о п р е о б р а з о в а н и е б у д е т в ы п о л н е н о , тольк о е с л и о б ъ е к т b a n k A c c o u n t в д е й с т в и т е л ь н о с т и и м е е т т и п S a v i n g s A c c o u n t .
При272Часть IV. Объектно-ориентированное программированиепервом в ы з о в е ф у н к ц и и P r o c e s s A m o u n t ( )оператор is вернет значение t r u e , но привтором вызове, к о г д а в ф у н к ц и ю б у д е т п е р е д а н о б ъ е к т B a n k A c c o u n t , о п е р а т о р i s вернет f a l s e , ч т о п о з в о л и т и з б е ж а т ь н е к о р р е к т н о г о п р е о б р а з о в а н и я т и п о в . Т а к а я в е р с и япрограммы н е г е н е р и р у е т о ш и б к у в р е м е н и в ы п о л н е н и я .С одной стороны, я настоятельно рекомендую вам защищать все выполняемыеп р е о б р а з о в а н и я о п е р а т о р о м i s в о и з б е ж а н и е в о з м о ж н ы х о ш и б о к в р е м е н и выполнения.
С другой стороны, я рекомендую избегать приведения типов вообще.Класс o b j e c tРассмотрим с л е д у ю щ и е с в я з а н н ы е к л а с с ы :publicpublicclassclassMyBaseClass{}MySubClass:MyBaseClass{}Соотношение м е ж д у э т и м и д в у м я к л а с с а м и п о з в о л я е т п р о г р а м м и с т у с д е л а т ь следующий тест в р е м е н и в ы п о л н е н и я :publicclassTest{publics t a t i cvoidGenericFunction(MyBaseClass//ЕслиобъектMySubClassif(msc{////.!=....mc)действительноmsc=mcasявляетсяподклассомMyBaseClass;null)то и обрабатываем.
продолжение ..его.В этом с л у ч а е ф у н к ц и я G e n e r i c F u n c t i o n ( )какподклассв состоянии различить подклассыкласса M y B a s e C l a s s с п о м о щ ь ю о п е р а т о р а a s .Н о как р а з л и ч и т ь д в а н е с в я з а н н ы х м е ж д у с о б о й к л а с с а с и с п о л ь з о в а н и е м т о г о ж еоператора a s ? О к а з ы в а е т с я , С # п р о и з в о д и т в с е к л а с с ы о т о д н о г о о б щ е г о п р е д к а —базового к л а с с а o b j e c t . Т а к и м о б р а з о м , л ю б о й к л а с с , к о т о р ы й я в н о н е н а с л е д у е тдругой к л а с с , н а с л е д у е т к л а с с o b j e c t .
А з н а ч и т , д в а с л е д у ю щ и х в ы р а ж е н и я объявляют к л а с с ы с о д н и м и т е м ж е б а з о в ы м к л а с с о м o b j e c t :classMyClasslclassMyClass2:object{}{}Общий б а з о в ы й класс o b j e c t позволяет н а п и с а т ь с л е д у ю щ у ю о б о б щ е н н у ю ф у н к ц и ю :publicclassTest{publics t a t i cvoidGenericFunction(object{MyClasslmcl=Глава 12. Наследованиеоaso)MyClassl;273if(mcl!=null){}//Используем//..объектmcl,полученныйпреобразованием.}Функция G e n e r i c F u n c t i o n ()м о ж е т б ы т ь в ы з в а н а д л я о б ъ е к т а л ю б о г о типа.
В ыр а ж а я с ь п о э т и ч е с к и , к л ю ч е в о е с л о в о a s и з в л е к а е т ж е м ч у ж и н у M y C l a s s l и з устрицыobject.Использование оператора asО п е р а т о р a s р а б о т а е т н е с к о л ь к о и н а ч е , ч е м о п е р а т о р i s . В м е с т о в о з в р а т а значеният и п а b o o l о н п р е о б р а з у е т о б ъ е к т с л е в а о т с е б я к т и п у с п р а в а , н о п р и э т о м возвращениеn u l l , е с л и т а к о е п р е о б р а з о в а н и е н е к о р р е к т н о — в м е с т о г е н е р а ц и и о ш и б к и времени, в ы п о л н е н и я п р и и с п о л ь з о в а н и и о б ы ч н о г о п р е о б р а з о в а н и я .