c l a s s MyClas s
{
s t a t i c p u b l i c f l o a t |
F l o a t T i m e s 2 ( f l o a t f ) |
{ |
|
|
|
/ / Все |
о т л и ч н о |
р а б о т а е т |
f l o a t |
f R e s u l t |
= 2 |
* f ; |
r e t u r n |
f R e s u l t ; |
|
} |
|
|
|
}
Константа 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.
приводит к следующему: c l a s s M y C l a s s
{
s t a t i c p u b l i c v o i d S o m e F u n c t i o n ( )
{
c h a r c l = ' a ' ; c h a r c 2 = ' 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 MyClas s
{
s t a t i c p u b l i c f l o a t F l o a t T i m e s 2 ( f l o a t f )
{
/ / З д е с ь и с п о л ь з о в а н о я в н о е f l o a t f R e s u l t = ( f l o a t ) ( 2 . 0 r e t u r n f R e s u l t ;
пр е о б р а з о в а н и е
*f ) ;
}
}
Результат умножения 2 . 0*f имеет тип d o u b l e , как и ранее, однако программист' явно указал, что он хочет преобразовать полученное значение к типу f l o a t , даже если это приведет к потере информации (см. главу 3, "Объявление переменных-значений").
Второй подход к проблеме может состоять в том, чтобы явно указать необходимы! тип константы:
378 |
Часть VI. |
Великолепные десятки |
Г л а в |
|
|
class M y C l a s s
{
s t a t i c p u b l i c f l o a t F l o a t T i m e s 2 ( f l o a t f )
{
/ / З д е с ь 2 . OF — к о н с т а н т а т и п а f l o a t f l o a t f R e s u l t = 2 . OF * f;
r e t u r n f R e s u l t ;
}
В этой версии функции использована константа 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
{
p u b l i c v o i d S o m e F u n c t i o n ( )
{
Y o u r C l a s s |
uc = new Y o u r C l a s s ( ) ; |
// M y C l a s s не и м е е т д о с т у п а к з а к р ы т о м у ч л е н у |
uc.nPrivateMember = 1; |
} |
|
} |
|
public c l a s s |
Y o u r C l a s s |
"{
private int nPrivateMember = 0;
}
Обычно такая ошибка не столь очевидна. Зачастую оказывается просто забытым де скриптор члена или всего класса, а по умолчанию член класса является закрытым. Так, nPrivateMember остается закрытым в следующем фрагменте исходного текста:
class |
M y C l a s s |
// |
Доступ к |
к л а с с у |
по умолчанию - i n t e r n a l |
( |
|
|
|
|
|
|
p u b l i c v o i d S o m e F u n c t i o n ( ) |
|
{ |
|
|
|
|
|
|
Y o u r C l a s s |
uc |
= |
new Y o u r C l a s s ( ) ; |
// M y C l a s s не и м е е т д о с т у п а к з а к р ы т о м у ч л е н у |
uc . n P r i v a t e M e m b e r = 1; |
|
|
} |
|
|
|
|
|
|
'public |
c l a s s |
Y o u r C l a s s |
|
|
( |
|
|
|
|
|
|
int |
n P r i v a t e M e m b e r |
= 0 ; |
/ / Этот |
ч л е н - з а к р ы т ы й ! |
Глава 16. Десять наиболее распространенных ошибок компиляции |
379 |
Кроме того, несмотря на то что функция S o m e F u n c t i o n () объявлена как public к ней нельзя обратиться из классов других модулей, поскольку класс MyClass сам себе является внутренним.
Мораль этой истории — всегда указывайте уровень защиты ваших классов и их чле нов. Кроме того, не объявляйте открытые члены во внутренних классах — это том сбивает с толку.
Данное сообщение указывает на то, что вы объявили переменную, но не присвоили ей никакого начального значения. Обычно это простой недосмотр, но такая ситуация может возникнуть, когда вы передаете переменную в функцию как out-аргумент, как показано в приведенном далее фрагменте исходного текста,
p u b l i c c l a s s M y C l a s s |
|
|
|
{ |
|
|
|
|
|
p u b l i c v o i d S o m e F u n c t i o n ( ) |
|
|
{ |
|
|
|
|
|
i n t |
n ; |
|
|
|
|
// |
Все в |
п о р я д к е , |
т а к к а к |
С# т о л ь к о в о з в р а щ а е т |
з н а ч е н и е |
// |
в п; |
в функцию |
з н а ч е н и е |
э т о й п е р е м е н н о й не |
п е р е д а е т с я |
S o m e O t h e r F u n c t i o n ( o u t n ) ;
}
p u b l i c v o i d S o m e O t h e r F u n c t i o n ( o u t i n t n )
{
n = 1;
}
В данном случае переменной п в функции S o m e F u n c t i o n () не присваивается ни
какого значения, поскольку это выполняется |
в функции SomeOtherFunctiond |
Функция 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.Когда вы запустили программу с помощью команды Debug ^Start without
Debugging, то получили сообщение Нажмите < E n t e r > д л я завершения п р о г р а м м ы . . ., но по какой-то причине не сделали этого (таким образом, вы-
380 |
Часть VI. Великолепные д е с я т и |
полнение программы продолжается), а вы переключились в Visual Studio 2005 и продолжили редактирование файла.
Примечание: если вы запустили программу посредством команды Debug^Start Debugging и забыли ее завершить, то Visual Studio 2005 запросит вас о том, не
следует ли завершить выполнение программы.
3.Вы попытались собрать программу заново, с новыми обновлениями. В этот мо мент вы и получаете рассматриваемое сообщение об ошибке в окне Error List.
Выполнимый (. EXE) файл блокируется Windows до тех пор, пока программа не прекратит работу. Visual Studio не в состоянии перезаписать заблокированный старый
.ЕХЕ-файл новой версией без полного завершения программы.
Чтобы исправить ситуацию, переключитесь на ваше активное приложение и заверши те его работу. Если это одно из консольных приложений из данной книги, просто нажми
те клавишу <Enter>. Вы также можете завершить программу из Visual Studio 2005 по средством команды меню Debug^Stop Debugging. После того как старое приложение
прекратит работу, соберите приложение заново.
Если вы не можете избавиться от ошибки таким способом, выйдите из Visual Studio 2005 и перегрузите компьютер. Если не сработает и это — ну, тогда не знаю, чем вам можно помочь...
Посредством этого сообщения С# пытается информировать о том, что вы перегру |
|
жаете метод базового класса без его перекрытия (см. детальное описание в главе 13, |
|
Полиморфизм"). Давайте рассмотрим следующий пример: |
|
public |
|
c l a s s |
B a s e C l a s s |
|
|
I |
|
|
|
|
|
|
public |
v o i d |
F u n c t i o n () |
v |
|
public |
c l a s s |
S u b c l a s s |
: B a s e C l a s s |
|
|
public |
v o i d |
F u n c t i o n ( ) / / h e r e ' s |
t h e o v e r l o a d |
|
{ |
|
|
|
|
|
|
} |
|
|
|
|
|
|
public |
c l a s s |
M y C l a s s |
|
|
|
public |
v o i d |
T e s t ( ) |
|
|
|
{ |
|
|
|
|
|
|
S u b c l a s s sb = new |
S u b c l a s s ( ) ; |
|
|
s b . F u n c t i o n ( ) ; |
|
|
|
} |
|
|
|
|
|
|
16. |
|
Десять |
наиболее |
распространенных |
ошибок компиляции |
381 |