1629295403-b876e2087bddebea4bc9666fb2377a02 (846199), страница 74
Текст из файла (страница 74)
Целое значениенАде умножается на число с плавающей точкой 2.0, что в результате дает значение типаdouble. С# не в состоянии автоматически сохранить значение типа d o u b l e в переменяй n F a c t o r e d A g e типа i n t , потому что при этом может оказаться потерянной информация — скорее всего, дробная часть числа с плавающей точкой.Некоторые преобразования не настолько очевидны, как в следующем примере:class M y C l a s s{staticpublicfloatFloatTimes2(floatf){// Г е н е р и р у е т с яfloat f R e s u l t =returnfResult;сообщение2 .
0 * f;обошибкеВы можете решить, что здесь все в порядке, так как везде используется тип f l o a t .Яо дело в том, что 2.0 имеет тип не f l o a t , a d o u b l e , d o u b l e , умноженный на f l o a t ,нет d o u b l e . С# не может сохранить значение типа d o u b l e в переменной типа f l o a tв-за возможной потери информации, в данном случае — количества знаков результата,но приводит к снижению точности (см. главу 3, "Объявление переменных-значений").Неявное преобразование легко запутывает неискушенного читателя.
В приведенном да|кфрагменте исходного текста функция F l o a t T i m e s 2 () работает вполне корректно:та16. Десятьнаиболее распространенных ошибок компиляции377classMyClass{staticpublicfloatFloatTimes2(floatf){/ / Все о т л и ч н о р а б о т а е тfloat fResult =2*f;returnfResult;}}Константа 2 имеет тип i n t . i n t , умноженный н а f l o a t , дает f l o a t , к о т о р ы йвполне может быть сохранен в переменной f R e s u l t типа f l o a t .Такое же сообщение об ошибке может возникать и при выполнении операций не"неестественными" типами.
Например, нельзя сложить две переменные типа char, неС# может при необходимости конвертировать переменную c h a r в значение int.приводит к следующему:classMyClass{staticpublicvoidSomeFunction(){} }char cl = ' a ' ;c h a r c2 = ' b ' ;// Я не знаю, ч т о э т о должно о з н а ч а т ь ,// н е в е р н о — х о т я и не по т о й п р и ч и н е ,// думаетеc h a r сЗ = cl + с 2 ;н о в с е р а в н о этоо к о т о р о й выСложение двух символов не имеет смысла, но С# все равно попытается это сделатьПоскольку сложение для типа c h a r не определено, он преобразует cl и с2 в значениетипа i n t и выполнит их сложение (технически c h a r представляет собой интегральныйтип).
К сожалению, результат этого сложения преобразовать обратно в c h a r не удастсябез помощи со стороны программиста (см. главу 3, "Объявление переменныхзначений").Большинство (хотя и не все) преобразований без проблем выполняется при их явномуказании. Так, следующая функция компилируется без каких-либо нареканий:c l a s s MyClass{staticpublicfloatFloatTimes2(floatf){// Здесь использовано явное преобразованиеfloat fResult =(float)(2.0 * f);returnfResult;}}Результат умножения 2 . 0 * f имеет тип d o u b l e , как и ранее, однако программист'явно указал, что он хочет преобразовать полученное значение к типу f l o a t , даже еслиэто приведет к потере информации (см.
главу 3, "Объявление переменных-значений").Второй подход к проблеме может состоять в том, чтобы явно указать необходимы!тип константы:378Часть VI. ВеликолепныедесяткиГлавclassMyClass{staticpublicfloatFloatTimes2(floatf){// Здесь 2.OF — к о н с т а н т аf l o a t f R e s u l t = 2 .
O F * f;returnfResult;типаfloat}В этой версии функции использована константа 2.0 типа f l o a t , а не d o u b l e , какпринято п о умолчанию, f l o a t , умноженный н а f l o a t , дает f l o a t .Данная ошибка указывает на попытку функции обратиться к члену, на обращениек которому она не имеет прав. Например, метод в одном классе может пытаться обратиться к закрытому члену другого класса (см. главу 11, "Классы"), как показано в приведенном фрагменте исходного текста,public c l a s s M y C l a s s{public void SomeFunction(){Y o u r C l a s s uc = new Y o u r C l a s s ( ) ;// MyClass не имеет д о с т у п а к закрытомуuc.nPrivateMember = 1;}}publicclass"{членуYourClassprivate int nPrivateMember = 0;}Обычно такая ошибка не столь очевидна.
Зачастую оказывается просто забытым дескриптор члена или всего класса, а по умолчанию член класса является закрытым. Так,n P r i v a t e M e m b e r остается закрытым в следующем фрагменте исходного текста:class M y C l a s s//Доступкклассупоумолчанию-internal(publicvoidSomeFunction(){Y o u r C l a s s u c = new Y o u r C l a s s ( ) ;// MyClass не имеет д о с т у п а к закрытомуuc . n P r i v a t e M e m b e r = 1;члену}'publicclassYourClass(int n P r i v a t e M e m b e rГлава16.Десять= 0 ;//Этотчлен-закрытый!наиболее распространенных ошибок компиляции379Кроме того, несмотря на то что функция S o m e F u n c t i o n () объявлена как publicк ней нельзя обратиться из классов других модулей, поскольку класс M y C l a s s самсебе является внутренним.Мораль этой истории — всегда указывайте уровень защиты ваших классов и их членов.
Кроме того, не объявляйте открытые члены во внутренних классах — это томсбивает с толку.Данное сообщение указывает на то, что вы объявили переменную, но не присвоили ейникакого начального значения. Обычно это простой недосмотр, но такая ситуация можетвозникнуть, когда вы передаете переменную в функцию как out-аргумент, как показанов приведенном далее фрагменте исходного текста,publicclassMyClass{publicvoidSomeFunction(){i n t n;// Все в п о р я д к е , т а к к а к С# т о л ь к о в о з в р а щ а е т значение// в п; в функцию з н а ч е н и е э т о й п е р е м е н н о й не п е р е д а е т с яSomeOtherFunction(out n ) ;}publicvoidSomeOtherFunction(outintn){n =1;}В данном случае переменной п в функции S o m e F u n c t i o n () не присваивается никакого значения, поскольку это выполняется в функции S o m e O t h e r F u n c t i o n dФункция S o m e O t h e r F u n c t i o n () игнорирует значение out-аргумента, как если 6ы|его не существовало вовсе.
(В главе 3, "Объявление переменных-значений", рассказывается о переменных, а ключевое слово o u t рассмотрено в главе 7, "Функции функций".)Обычно это сообщение повторяется несколько раз. И почти всегда означает, что вызабыли завершить выполнение программы перед ее пересборкой. Другими словами, высделали следующее.1. Успешно собрали программу.2. Когда вы запустили программу с помощью команды D e b u g ^ S t a r t withoutDebugging, то получили сообщение Н а ж м и т е < E n t e r > д л я завершенияп р о г р а м м ы . .
., но по какой-то причине не сделали этого (таким образом, вы-380Часть VI. Великолепные десятиполнение программы продолжается), а вы переключились в Visual Studio 2005и продолжили редактирование файла.Примечание: если вы запустили программу посредством команды Debug^StartDebugging и забыли ее завершить, то Visual Studio 2005 запросит вас о том, неследует ли завершить выполнение программы.3. Вы попытались собрать программу заново, с новыми обновлениями. В этот момент вы и получаете рассматриваемое сообщение об ошибке в окне Error List.Выполнимый (. EXE) файл блокируется Windows до тех пор, пока программа не прекратит работу. Visual Studio не в состоянии перезаписать заблокированный старый.ЕХЕ-файл новой версией без полного завершения программы.Чтобы исправить ситуацию, переключитесь на ваше активное приложение и завершите его работу.
Если это одно из консольных приложений из данной книги, просто нажмите клавишу <Enter>. Вы также можете завершить программу из Visual Studio 2005 посредством команды меню Debug^Stop Debugging. После того как старое приложениепрекратит работу, соберите приложение заново.Если вы не можете избавиться от ошибки таким способом, выйдите из Visual Studio2005 и перегрузите компьютер. Если не сработает и это — ну, тогда не знаю, чем вамможно помочь...Посредством этого сообщения С# пытается информировать о том, что вы перегружаете метод базового класса без его перекрытия (см. детальное описание в главе 13,Полиморфизм").
Давайте рассмотрим следующий пример:publicclassIBaseClassvpublic v o i d F u n c t i o n ()publicclasspublicvoidSubclass:Function()BaseClass//here'stheoverload{}publicpublic{classvoidMyClassTest()S u b c l a s s s b = newsb.Function();Subclass();}16. Десять наиболее распространенных ошибок компиляции381Функция T e s t () не может обратиться к методу B a s e C l a s s . F u n c t i o n () из onекта подкласса s b , поскольку он скрыт методом S u b c l a s s .