Visual Basic, .NET, ASP, VBScript
 

   
 
Описание для автора не найдено
 
     
   
 

Откровенно говоря, я начал писать сегодняшнюю свою статью без особого энтузиазма. Вещи о которых я буду рассказывать очень нудные и размышлять о них скучно. В свою очередь читателям мой опус пойдет с большим трудом и я думаю что далеко не все из них поймут, о чем это я тут вообще… Но выбора у меня пожалуй что и не остается. Написав всего две статьи по тематике VBN (я имею ввиду 1 и 2 впечатление о VB7) я что говорится «засветился» как специалист в этой области. Если первое время, после опубликования статей, я получал письма больше «философского характера» (в конце статьи я постараюсь уделить немного времени разбору почты), то на сегодняшний день ситуация изменилась радикально. В моем почтовом ящике все больше и больше писем с извечным вопросом: «Что делать? Как изучить эту беду и побыстрее?». Ответить конечно на такой вопрос в пределах одной статьи просто невозможно. А вообще я и не пытаюсь. Моя сегодняшняя задача обратить внимание читателей на несколько очень серьезных мелочей, без знания которых освоить технологию NET просто невозможно.

Небольшой анализ текущей ситуации.

Спустя почти год после начала распространения VS.NET все выглядит примерно так (конечно это моё субъективное мнение):

«Новая» технология очень понравилась ничего не пишущим программистам и журналистам. И те и другие просто соревнуются сейчас в распевании псалмов «славься, славься NET» - кто громче. Вот только кто бы из них меня своей программой порадовал написанной по этой самой технологии (моя мыльница снизу статьи).

Пишущие программисты спрятали свои головы от новой технологии в песок (все равно как те страусы), авось пронесет. Нет, не пронесет к сожалению. Таки придется изучать. И хоть VSN и выглядит как очень волевое решение Майкрософт, но это решение тем не менее состоялось. Фирма Борланд уже заявила о начале разработки NET-версий своих продуктов. А других конкурентов вроде как и не было (под PC-Windows). Что касается других платформ, то там все по прежнему тихо. Там не только о NET, о Майкрософт мало кто слышал.

Стоящих книг о NET на русском языке пока не появилось. Можно даже сказать что книг нет совсем, да и статей тоже нет. В принципе это было бы нормальным решением вопроса. Взять классную книгу и залечь с ней на диван, примерно так на неделю. А через неделю встать с дивана и сразу начать писать Net-программы. Фантастика? – Да. Хотя ведь с VB6 все было именно так.

Более или менее прояснился вопрос со сроками, в которые Net должна овладеть мозгами программеров и их компьютеров. Это примерно с 2004 по 2009 год. Многим этот срок возможно покажется очень долгим. А быстрее к сожалению не получается…, у Майкрософт. Пока ведь написана только VSN. Сейчас в деле Windows.Net. Дальше очередь Office, потом VBA, все сервера и так далее и тому подобное.

Деловой программистский мир весьма серьезно обеспокоился. Поставьте себя на место технического директора какой ни будь фирмы, которая пишет серийный софт под Windows и с этого живет. В 2004 году надо выдать на-гора Net-версию своего продукта. А чтобы это случилось, начинать писать надо уже сегодня. А как? Программистов нет. Операционки пока тоже нет. Как результат – просто дикий спрос на специалистов по технологии Net. Началась паника и среди рядовых программистов: если найдут специалистов по Net, куда нас тогда денут? Короче говоря – на бирже паника, эффект цепной реакции.

Один из самых интересных вопросов которые сегодня задают: а сколько времени надо изучать NET? Постараюсь ответить на этот вопрос как смогу. Давайте вначале произведем некоторые весьма приблизительные расчеты. В Net примерно от 4 до 9 тысяч классов (цифры эти взяты из источников которым я склонен доверять). Наиболее часто встречается цифра в 6000 классов, давайте на ней и остановимся. У каждого класса (в среднем) 5 членов. Не трудно подсчитать число классов и их членов, которые необходимо изучить для 100% овладения технологией: 6000*(1+5)=36000. Конечно, изучать на все 100, для того чтобы писать программы, совсем не обязательно. Согласно исследований произведенных для Си-подобных языков, глубины познаний должны быть таковыми: 10% – уровень начинающих (а это между прочим 3600 ключевых слов языка надо изучить); для профи необходим уровень минимум в 60% (я наверное до профи не дотяну, жизни не хватит). Ну что ж, после того как я так оптимистически обрисовал вам ситуацию, каждый читатель вправе сам решать: на какой уровень Net и с какого разбега ему хочется запрыгнуть. Могу сказать только про себя. Весь последний почти год я провел за учебниками (как в старые добрые студенческие годы). Похоже что уровня начинающих за это время я достиг. Но единственное что мне этот уровень дал, это только четкое понимание того как много еще следует изучить. И мне откровенно говоря дата в 2004 год совсем не кажется долгой.

И еще одно. Как это не парадоксально, но мы, Вб-шники оказались в более определенной ситуации чем Си-шники. По крайней мере у нас уже есть язык который нам осталось только изучить. А с Си ситуация очень туманная. Майкрософт включила в VSN две версии Си. С++ был включен в комплект по одной простой причине - эта версия Си является общепризнанным языком программирования, узаконенным соответствующей спецификацией в комитете ANSI (США). Если бы С++ вдруг исчез, все единодушно заявили бы, что VSN не поддерживает стандартных языков программирования. С другой стороны, абсолютно ясно, что С++ исчезнет из последующих версий VS, как только спецификация C# будет хоть кем ни будь утверждена. На сегодняшний день коалиция по продвижению C# состоит в основном из трех фирм. Это Microsoft, Intel и Hewlett-Packard. Имена эти конечно многого стоят. Но я честно говоря слабо понимаю, какова заинтересованность производителя микросхем и производителя железа в развитии прикладного языка высокого уровня. Двухлетние попытки пропихнуть спецификацию C# через ANSI не дали никакого результата. И теперь ставка делается на ECMA (европейский аналог ANSI).

Языки программирования высокого уровня.

Я отношусь к тем людям, которые делят языки программирования высокого уровня на языки более и менее высокого уровня. В зависимости от уровня языка изменяются требования например к таким вещам, как знание программистом железа. Уровень языка определяет его универсальность и трудозатраты на разработку программного обеспечения. Давайте именно с этих позиций сравним два пакета программирования: VS6 и VSN.

Языком более высокого уровня в VS6 считался VB6. Средствами языка (без применения дополнительных компонентов) можно было рисовать на экране, осуществлять бинарный ввод – вывод в файл и тому подобное. VB6 всегда ругали за то что все эти возможности были очень примитивными. Но все-таки эти возможности были и их вполне хватало например для того чтобы нарисовать свой контрол или обеспечить свое приложение собственным форматом файла. К несомненным достоинствам VB6 в этой области следует отнести то, что эти возможности было легко изучить и программисту абсолютно не требовалось знание железа. Те, кого такое положение не удовлетворяло, всегда могли подсесть на VC6.

VC6, язык значительно более низкого уровня чем VB6. Максимальное, что можно сделать средствами этого языка, это организовать цикл или блок условных переходов. Для того чтобы рисовать или выводить в файл необходимо было использовать или API интерфейс или классы поставляемые совместно с языком. При этом возможности конечно были самые широкие и универсальные (но это только теоретическое утверждение). Программисты которые действительно владели такими возможностями были большой редкостью. Для того чтобы стать профи, необходимо было много чего изучить, а потом еще много чего написать. Вообще, программирование Windows приложений на Си это не удел одиночек, это конвейер в котором занято большое количество специалистов. Одни люди планируют задачу, другие её пишут, третьи монтируют и компилируют, четвертые тестируют, пятые документируют функциональность и так далее.

Есть еще и третья сторона у того что я сейчас поведал о VS6 – это ассемблер (я представляю себе квадратные глаза читателей). Тут дело вот в чем. Применительно к очень большому спектру задач (например таких как компрессия видео в реальном масштабе времени), Си является очень расточительным на ресурсы процессора. И в таких ситуациях есть только единственный выход – ассемблер. Причем речь не идет о написании программ полностью на ассемблере. Вы пишете на Си, куски ассемблера появляются только там где это надо.

Теперь о возможности использования всех трех уровней в одном проекте. Такая возможность была, хотя скорее как исключение из общепринятых правил. Ассемблер вкраплялся в исходник на Си. В свою очередь исходник Си оформлялся как COM. COM передавался в VB. Конечно, была большая масса сложностей с отладкой и многоступенчатым компилированием. И тем не менее я знаю большое число проектов написанных именно по такой схеме (речь идет о специализированных программах по управлению технологическим оборудованием).

На фоне таких возможностей VS6, VSN кажется просто безобразным карликом. Ни о каком ассемблере и речи не может идти (с учетом требования платформенной независимости и двухэтапного компилирования). А VB опустили до уровня Си. Сильно возросла конечно поддержка Интернет - технологий, но зачем такая поддержка нужна, когда я просто хочу сжать видеосигнал?

Общее моё впечатление об изменениях в VB примерно такое (на сегодняшний день). Я не увидел ни одной серьезной чисто технической причины для такого радикального изменения языка. Все старые возможности вполне реально было реализовать с учетом введения CLS спецификации. Просто Майкрософт сама взвалила на свои плечи сильно непомерную задачу и теперь ей просто не хватает времени сделать все по человечески.

Что такое классы.

Программисты работавшие ранее на VB всегда имели достаточно мутное представление о классах. Есть и другая категория людей. Таковые извлекают из своей головы целый вагон очень научных определений классов и определений связанных с объектной ориентированностью и наследованием, но проку от этих знаний нет никакого - теория совсем не используется на практике. На мой взгляд, ключом к пониманию сущности классов является именно практическая сторона их использования. Поэтому я не буду давать определения классов, а лучше расскажу как это работает на практике.

Давайте рассмотрим очень грубый пример. К Вам приходит клиент и в течении некоторого времени рассказывает Вам о той складской базе данных, которая очень необходима для его фирмы. Вы оговариваете сроки и цену. Клиент удаляется в обнадеженном состоянии, а Вы направляете свои стопы куда-нибудь в ночной клуб, для того чтобы немного расслабиться перед большой работой и заодно наметить план предстоящих действий. В самый разгар такого приятного вечера, в Вашей голове вдруг всплывает роковая мысль: точно такую базу данных я уже писал, ох когда же это было, да года три тому назад. Вы как ошпаренный, выскакиваете из клуба, хватаете тачку и мчитесь к своему компу: какая удача и делать ничего не надо, только найти программу и деньги у заказчика забрать... Но реальность оказывается более суровой. И программа нашлась, и её исходник имеется. Вот только система поиска в базе данных работает совсем не так, как это надо. Ну ничего сейчас исправим, так, а ну исходник, ходь сюда. Елки-палки, да кто писал этот бред, да неужели я три года тому назад, а это вообще может работать? Короче говоря, ночь полностью испорчена и ближе к утру Вы принимаете решение писать программу с нуля. Какой облом.!!!

В том что я сейчас рассказал нет ничего неправдоподобного. Три года (согласно исследованиям) это как раз тот самый срок (для среднестатистического программиста) за которые он полностью изменяет свой стиль. Я даже больше скажу. Два программиста работающих рядом, стол в стол, в плане реализации задачи совсем не понимают друг друга. Стоит только взять в руки чужой исходник (или свой но очень старый) и сразу появляется масса вопросов и еще больше советов. А как тогда работать над проектом большой толпой? Вот тут на выручку и приходят классы.

Большая задача (масштаба приложения) разбивается на более мелкие, но обладающие вполне законченной функциональностью. Те в свою очередь дробятся опять и так продолжается до тех пор, пока дальнейшее дробление теряет смысл. Например, если на первом круге дробления могла получиться задача с функциональностью «перерисовать окно приложения на экране», то после полного дробления получаются функциональности вида «нарисовать на экране точку». После дробления, производится анализ и оптимизация. Например, несколько функциональностей вида «нарисовать на экране точку», вполне можно объединить в одну вида «нарисовать на экране точку в заданных координатах и заданным цветом». Следующий этап, это максимальное использование функциональностей поставляемых в библиотеке языка программирования. Несомненно, функциональность вида «нарисовать на экране точку в заданных координатах и заданным цветом» там имеется, но надо знать это наверняка и знать как это называется, и где лежит. (Но знаете когда это действительно большой облом? Это когда Вы вдруг случайно узнаёте, уже когда программа почти написана, что в библиотеке языка была функциональность вида «перерисовать окно приложения» и целую кучу работы Вы сделали совсем зря.) Все функциональности, которые не удалось вытащить из библиотек, приходится писать ручками. Каждая такая функциональность обзывается членом класса. Члены группируются в классы. И каждому из имеющихся программистов вручается один или несколько классов для воплощения в исходник.

При этом сразу оговаривается одно очень важное условие. Каждый программист является полным хозяином своего класса. Он пишет его как умеет или как считает нужным. Его ответственностью перед коллективом сотоварищей, являются обеспечение поставленной перед ним функциональности и сроков выполнения задачи.

Теперь о наследовании. Так очень часто бывает, что у Вас уже есть класс очень похожий на требуемую функциональность. А как сделать так, чтобы не писать все с нуля, а только чуть подправить функциональность? Очень просто. Надо унаследовать имеющийся класс и переписать те его функции которые работают не так как надо. В результате наследования Вы получаете производный класс созданный на основе исходного (базового) класса. Переписывание функций возможно только на уровне членов класса (это для того чтобы не было нужды ковыряться в исходнике базового класса). Вы берете базовый класс и смотрите на его функциональность (есть члены класса, которые осуществляют определенную работу). Если что-то Вам не нравится из членов класса, Вы берете это, отрываете и выбрасываете. А к тому что осталось, можно прилепить новые члены (естественно написав для них исходный текст программы). Давайте вернемся к примеру с базой данных. Если бы старая программа была оформлена как класс, а система поиска как член этого класса, писать новую программу совсем не потребовалось бы.

Похоже что я все это очень красиво изложил. Теперь самое время все изгадить. На практике классовое программирование применяется очень редко (результаты исследований). И тому есть очень серьезные причины. Первое. Создавать класс необходимо с мыслью о том, что этот класс возможно будет когда-нибудь унаследован, а это требует дополнительных усилий. И второе. Вспомните пожалуйста, когда Вы документировали свою программу последний раз. Я думаю что очень многие читатели ответят так: вообще никогда. А без очень скрупулезного документирования функциональности, классы вообще ничего не стоят. Представьте себе гору из 6000 классов поставляемых с VSN, на которые нет ни строчки документации.

Типы переменных.

Понятия о типах переменных являются базовыми для любого языка программирования высокого уровня. Применительно к VBN, все понятия о типах переменных (в тех статьях и книгах которые я прочел к сегодняшнему дню) описываются достаточно поверхностно. Все описание сводится к таблице с типами переменных поддерживаемых языком. Такие подходы вполне были приемлемы для VB6. Но когда VB опустили, таких знаний становится явно недостаточно.

Я начну вот с чего. Типы переменных всегда описывались классами. В Windows-среде, выделение физического пространства в ОЗУ под переменную и последующий доступ к этому пространству очень сложные процедуры, которые сопровождаются многочисленными вызовами функций API и обработке приходящих в ответ сообщений окну программы. Всю эту работу и делали классы. Просто эти классы были скрытыми и программист о них совсем не думал. Теперь нам эти классы показали и при этом настоятельно рекомендуют изучить эти классы самым тщательным образом. Я присоединяюсь к таким рекомендациям (а другой альтернативы нет) и попросту привожу список классов рекомендованных для изучения:

System.Boolean

System.Byte

System.Char

System.Int16

System.Int32

System.Int64

System.Double

System.Single

System.Object

System.DateTime

System.Decimal

System.String

System.ValueType

System.Array

Microsoft.VisualBasic.Conversion

Microsoft.VisualBasic.Information

Microsoft.VisualBasic.VBFixedArrayAttribute

Microsoft.VisualBasic.Interaction

И еще небольшой комментарий. Все классы описывающие типы переменных определены в Mscorlib.dll (а это .NET Framework). VBN просто наследует часть этих классов (почему не все я так и не понял). А результат такой: в VBN типов переменных немного меньше чем в .NET Framework (наверное это сделано потому, что Бейсик все-таки язык программирования для начинающих). Но я рекомендую Вам изучить все классы (не только для общего развития а и для программирования тоже).

Зоны видимости.

Только когда начинаешь изучать зоны видимости в VBN, только тогда приходит понимание того, для чего зоны видимости были введены в VB6. Они там были исключительно для удобства программирования. Каждой из зон видимости был сопоставлен четкий логический смысл вполне совпадающий с человеческой логикой мышления. В VBN атрибуты зон видимости это чистой воды директивы компилятору. Следуя этим директивам, компилятор располагает запись о объявляемом элементе в той или иной таблице (потока, процесса, задачи и тому подобное). Для того чтобы окончательно постигнуть смысл зон видимости в VBN надо достаточно хорошо разбираться в очень сложных процессах происходящих при компилировании и выполнении программы. Действительный объем вопроса может измеряться не статьями, а книгами и годами практического применения знаний. Но любой даже очень сложный вопрос надо начинать с чего-то изучать. Поэтому я постараюсь дать некоторые начальные рекомендации.

Вначале полный список этих самых атрибутов видимости: Dim, Static, Public, Private, Protected, Friend, Protected Friend, ReadOnly. Вообще, Static и ReadOnly это не совсем зоны видимости в том смысле как мы привыкли это понимать. Но это директивы компилятору и ставятся они как раз там, где ставятся атрибуты видимости, и именно поэтому я все свалил в один список. Для каждого из этих ключевых слов Вы найдете по абзацу комментария в MSDN, на большее не рассчитывайте.

Теперь список элементов к которым эти атрибуты применяются: классы, переменные и процедуры. При этом следует иметь ввиду, что переменные и процедуры будут всегда объявляться внутри классов (за редким исключением - внутри модулей). А поэтому есть определенные закономерности между зоной видимости при объявлении класса и зонами видимости при объявлениях членов этого класса. MSDN имеет краткие рекомендации и по этому поводу, но все так разбросано, что знания Вам придется собирать по крупицам.

При объявлении классов и их членов используется ряд атрибутов которые управляют процессами наследования. Вот этот список: Shared, Shadows, MustInherit, NotInheritable, Overridable, NotOverridable, MustOverride, Overrides. Хотя это совсем другая тема для разговора, я все-таки должен предупредить о следующем. Существуют закономерности между атрибутами наследования и атрибутами видимости.

Теперь о том как это все следует изучать. Прежде всего теория: изучите описание всех приведенный мной ключевых слов в MSDN. А дальше конечно практика. При объявлении класса и всех его членов всегда явно указывайте как атрибут видимости так и атрибут наследования. Если этого не делать, будет применен атрибут по умолчанию, но знаний при этом у Вас не прибавится. Запускайте программу на выполнение и следите за сообщениями компилятора. Думайте, анализируйте и исправляйте ошибки.

Особенности изучения контролов.

Основное назначение контролов не изменилось. Вы располагаете контролы на форме, устанавливаете их свойства в необходимые значения (для придания контролам требуемой функциональности) и в процедуры событий контролов вписываете требуемый код. Короче говоря все как в VB6. Только одно отличие. Контролы стало очень сложно изучать.

В VB6 каждый контрол представлял собой законченный COM-объект. Вы брали такой COM-объект, изучали все свойства, методы и события связанные с ним, и в принципе Вам все становилось ясно. В VBN контролы это классы. Причем все эти классы наследуют другие классы, а те классы еще чего-то там наследуют. Поэтому под изучением контрола следует понимать изучение всей родословной в цепи его наследования. Дальнейшее повествование я продолжу на примере.

Я для примера выбрал один из самых простых контролов из библиотеки .NET Framework под названием ProgressBar (полоса выполнения процесса). Его родословная показана на рисунке:

О чем этот рисунок нам говорит. У класса ProgressBar приличная родословная (она приведена в разделе под названием Bases and Interfaces). Этот класс унаследовал класс Control, который в свою очередь унаследовал класс Component, который в свою очередь унаследовал класс MarshalByRefObject и который в свою очередь унаследовал класс типизирующий переменные Object. Все остальное (обозначено на рисунке пиктограммами типа «два разных кольца с перемычкой») это интерфейсы. На первом этапе изучения VBN о интерфейсах можно не думать. Это развлечение скорее для теоретиков (вот так поразминаешься с интерфейсами, а потом глядишь и диссертацию написал).

Теперь о последовательности изучения контрола. Надо двигаться по родословной снизу вверх. Вначале класс Object. Просто берете и изучаете все его члены (в самом максимальном случае бывает 4 категории членов класса: методы, свойства, события и константы) на предмет их функциональности. Идея вот в чем. Если при движении вверх по родословной с членом класса чего-нибудь не случится (он не будет перегружен вышестоящим по родословной классом) то этот элемент станет равноправным членом класса ProgressBar (вот вам и пример наследования в действии). Потом переходите к классу MarshalByRefObject и опять изучаете про него все. В добавок проверяете, не перегрузил ли этот класс члены нижестоящих классов (если попался член класса с именем которое было у члена класса пониже, то это и есть как раз та самая перегрузка), а если перегрузил, то как изменилась функциональность члена класса. Так надо добраться до самого верха родословной, то есть до класса ProgressBar. Все что останется в вашей голове после многократной перегрузки членов класса и будет функциональностью класса ProgressBar.

Еще несколько штрихов. При изучении свойств и методов обращайте внимание на типы данных этих свойств и типы данных параметров методов. Если Вам встретится знакомый тип данных (ну например Boolean или String), значит Вам повезло на этот раз. Но если тип данных окажется составным (с точкой внутри) – считайте что вам повезло вдвойне (вы сняли джек-пот), это ссылка на класс который тоже надо изучить.

Изменения в декларировании процедур событий для контролов тоже есть небольшие. Вот пример заголовка процедуры события Click (щелчок мышью) для контрола с именем Button1:

Private Sub Button1_Click(ByVal sender As System.Object, _
                                                 ByVal e As System.EventArgs) Handles Button1.Click

Я расскажу об этом только то, чего нет в MSDN. Первый параметр с именем «sender» передает в процедуру обработки события объектную ссылку на объект (класс загруженный в ОЗУ при выполнении программы) для которого событие было сгенерировано, то есть на сам контрол. Второй параметр с именем «e» вообще ничего не означает (в данном случае). То есть, если Вы видите на месте второго параметра (а их всегда будет два) переменную типа System.EventArgs, то это Вам повезло – этот параметр ничего не значит, он так для мебели. Но если этот параметр другого типа, то это джек-пот – ссылка на класс, который надо изучать.

Теперь о перечне самих контролов. Вы найдете его в панели инструментов VBN. Классы описывающие эти контролы имеют точно такие имена.

Пространства имен.

Термин «пространство имен» программистам VB6 доселе был неведом. Все очень просто. Если бы список из 6000 классов поставляемых с VSN был бы алфавитным, в нем никто никогда и ничего не нашел бы. Это был бы просто очень и очень большой список. Потому классы решили разбить на функциональные группы, каждая из которых и называется пространством имен. Таких пространств получилось достаточно много и в них поначалу тоже можно запутаться. Зато классы пересчитать теперь совсем невозможно.

Чтобы этот раздел не казался совсем коротким, я приведу несколько картинок из окна Object Browser на которых покажу наиболее важные пространства имен (Вы обязательно должны будете их изучить).

В пространстве имен System из .NET Framework на первом этапе достаточно изучить только классы определяющие типы переменных (я уже об этом говорил):

Сразу после этого рекомендую изучить пространство имен VisualBasic причем все. Это все что осталось от VB и много времени это не займет:

Теперь работа посложнее. В пространстве имен System.Windows.Forms сосредоточены классы описывающие контролы. Этих классов много и придется изучать все данное пространство имен:

В пространстве имен System.Drawing расположено все что связано с графикой и цветом. Даже если вам надо только менять размеры контролов из кода программы, вам придется использовать классы этого пространства имен:

И в заключение, пространство имен System.IO которое отвечает за ввод – вывод в файл и в консоль:

Все остальные и многочисленные пространства имен осваивайте по мере необходимости и наличия свободного времени.

Три сегмента памяти - три источника и три составные части програмизьма.

Самые простые вещи мы уже разобрали. Вдохните поглубже, будем нырять.

Успех программирования на VBN будет теперь зависеть от того, насколько глубоко Вы знаете железо (это мое пророчество). Теперь будет недостаточно знаний на уровне: материнская плата, винчестер, блок питания. Надо погружаться на уровень шины адреса и данных процессора. Без знаний таблиц виртуальной памяти и прерываний думаю пока можно обойтись (ну хотя бы до выхода следующей версии VSN). А пока Вы не обзавелись достаточным количеством книг по железу, я расскажу о том, без чего я просто не смогу продолжить свою статью. Вот Вам рисунок для созерцания бинарной действительности:

Что на нем показано. Объект подготовленный к выполнению загружен в ОЗУ процессора и при этом он лег на три сегмента этого самого ОЗУ.

В сегменте программы располагаются машинные коды исполняемых команд процессора. Эти команды когда-то были исходником программы и над ними уже потрудился компилятор. Регистр PC хранит в себе адрес той машинной команды, которая будет выбрана из памяти следующей для передачи на исполнение в АЛУ процессора. При выборе такой команды содержимое PC увеличивается на 1. Таким образом процессор перемалывает все команды расположенные подряд в сегменте программы. Этот процесс длится до тех пор, пока одна из команд не заставит выполнить явную перегрузку значения регистра PC. Как правило, такой переход предназначен для того чтобы процессор начал обрабатывать код совсем другого объекта уже загруженного в ОЗУ. Для того чтобы процессор мог вернутся к коду текущего объекта и вернутся именно в точку где процесс выполнения был прерван, старое значение регистра PC сохраняется в сегменте стека. При этом значение PC просто переписывается в ячейку ОЗУ на которую указывает регистр US, значение US изменяется на 1, после чего в PC загружается новое значение. Возврат к выполнению текущего (или предыдущего) объекта выполняется в обратной последовательности.

Давайте сразу (пока я не забыл) остановимся на одной особенности процесса выполнения программы. В этом процессе уже нет имен процедур (или если Вам угодно, имен членов классов). Переход может осуществляться только к адресам адресного пространства. Применительно к сегменту стека тоже есть одна особенность. В этом сегменте адресного пространства нет вообще. Всегда доступна только одна ячейка, на которую указывает содержимое регистра US. Для доступа к другим ячейкам стека, US необходимо прокручивать на заданное смещение. (Это я сказал для людей желающих узнать как в стеке сохраняются переменные.)

Теперь о сегменте данных (его еще называют кучей). Он характеризуется только адресным пространством (имен переменных тоже нет). Процессор, следуя указаниям своих команд, может обратиться по любому (но конкретному) адресу сегмента данных для того чтобы сохранить или прочитать значение этого адреса.

Теперь о великом таинстве процесса компиляции, о компоновке. Перед тем как приложение будет выполняться, оно должно быть загружено в ОЗУ процессора. На первом этапе, операционная система анализирует заголовок загружаемого EXE файла на предмет требуемых ресурсов ОЗУ. Далее в ОЗУ выделяются три сегмента строго запрошенных размеров и в них начинают сваливаться откомпилированные объекты. Я могу сравнить процесс загрузки объектов в ОЗУ с идеально собранным тетрисом (абсолютно без зазоров). После загрузки, в PC загружается необходимый адрес и программа начинает свою работу. А причем здесь компилятор? В его обязанности входит точный расчет всего процесса загрузки и вписывание конкретных требований к размерам сегментов памяти в заголовок EXE файла.

Раннее и позднее связывание.

Меня всегда очень веселили разговоры о связывании в отрыве от проблем компоновки объектов в сегментах ОЗУ. Теперь, когда я очень поверхностно проблемы компоновки изложил, давайте поговорим о связывании.

Каждый объект реально загруженный в ОЗУ имеет одну или несколько точек входа в его машинный код. Эти точки характеризуются конкретными значениями адресов в сегменте программы. Чтобы начать выполнение объекта, заданное значение нужно просто загрузить в регистр PC. Аналогичная ситуация с переменными сохраненными в объекте. Для того чтобы получить доступ к переменной сохраненной в куче, необходимо знать адрес ячейки памяти в которой эта переменная сохранена. Так вот, если компилятор смог точно рассчитать расположение объекта в ОЗУ, он все обращения к элементам этого объекта (как из самого объекта так и из других объектов) просто заменит на конкретные адреса адресного пространства и мы получим раннее связывание данного объекта.

А что бывает если компилятор не смог выполнить такого расчета? В этом случае компилятор начинает создавать таблицы обращений (вернее резервировать место под них). В каждой строке такой таблицы содержится адрес входа в элемент объекта. Конкретный адрес заносится в строку после того как объект будет реально загружен в ОЗУ (этот процесс называется динамической компоновкой на этапе загрузки). Вместо ссылок на конкретные адреса элементов объекта, в коде программы указываются ссылки на строки таблиц обращений. Для управления таблицами обращений компилятор генерирует специальные объекты (полностью автоматически и без участия программиста). Точного названия этот вид связывания не имеет. Одни люди называют это связывание ранним, а другие - средним.

И наконец самый тяжелый случай. Это когда компилятор не может определить количества элементов в объекте, которые необходимо указать в таблицах обращений. Это и есть позднее связывание. В таком случае на этапе загрузки объекта в ОЗУ приходится генерировать специальные таблицы в которых явно присутствует имя процедуры или переменной и реальный адрес расположения элемента в ОЗУ. Но как уже откомпилированный код должен ссылаться на такие таблицы (ссылок по именам процессор не понимает)...

Самое время поговорить о значении связывания применительно к VBN. В эпоху VB6 о связывании говорили исключительно с точки зрения быстродействия. Конечно, обработка таблиц расположения требовала ресурсов процессора, а других проблем вроде как и не было, об этом разработчики VB6 очень сильно позаботились. Но теперь встает на передний план вопрос тестирования программ. Среднее и позднее связывание является потенциальным источником возникновения ошибок защиты памяти. Что произойдет если загружаемый в ОЗУ объект вдруг окажется по размеру больше чем на это рассчитывал компилятор? А что произойдет если в процессе выполнения загруженный объект захочет изменить свои размеры? Я так понимаю, что в ближайшие годы по этому поводу будет написано очень много интересных книг, совсем не меньше чем их было написано применительно к Си-подобным языкам.

Классы и объекты.

Я так понимаю, что в головах читателей возникла некоторая неразбериха. Вначале я говорил о классах, потом классы куда-то подевались и пошел разговор о объектах. Есть еще такие понятия как экземпляры классов и объектные ссылки, которые все запутывают окончательно. Буду вносить ясность.

Классы это вещь абсолютно абстрактная. Классы существуют только в головах программистов когда те выясняют между собой кто, как и когда будет писать исходник программы. После того как к классу прикоснется компилятор, класс перестает существовать, а вместо него появляется исполняемый (машинный) код программы, который в конечном счете будет загружен в сегмент программы. Но есть еще два сегмента ОЗУ про которые не следует забывать. Эти сегменты заполняются при создании экземпляра (правильнее сказать исполняемого экземпляра) класса. Это происходит когда в программе вызывается конструктор этого класса New (хоть явно, а хоть не явно - это все равно). Вот в этот момент класс начинает существовать как объект. Ситуация становится еще более интересной когда конструктор вызывается несколько раз для одного класса. Здесь возможно несколько вариантов. Для каждого экземпляра класса создается новый объект на всех трех сегментах. Или по другому. Создается только новая база в сегменте данных, а сегмент программ один на несколько экземпляров класса. И управляют этим процессом атрибуты наследования. Что касается объектных ссылок, то это таблицы расположения ссылающиеся на загруженные экземпляры классов; каждая объектная ссылка - отдельная таблица (но сам объект при этом один и тот же).

Думаю что мне удалось в самых общих чертах рассказать о тех очень сложных процессах, которые происходят в компьютере при выполнении программ. Этих сведений конечно мало. Но на большее меня просто не хватило. И я надеюсь что каждый из читателей найдет в себе силы обратиться к специализированной литературе за расширением и углублением этих знаний. Ибо, чем больше знаний, тем меньше синих окон будет появляться на экране.

Взаимодействие процессов.

Этот раздел возможно самый важный из всей моей сегодняшней статьи. Хотя очень много о взаимодействии процессов я рассказать не смогу. В MSDN данная проблема освещена очень поверхностно и восполнять пробелы в знаниях приходится путем экспериментов. А достаточного времени на эти самые эксперименты пока не нашлось.

Каждая программа запущенная на выполнение в среде операционной системы должна взаимодействовать с этой операционной системой. Что подразумевается под таким взаимодействием. Во-первых, программа должна иметь доступ к ресурсам операционной системы. Под ресурсами я подразумеваю функциональности обеспечиваемые средой (или точки входа в регистр программы) и доступ к содержимому сегмента данных. Во-вторых, операционная система должна иметь точно такой доступ к ресурсам выполняемой программы. Давайте вначале рассмотрим как такое взаимодействие организовывалось до VSN.

Начинать надо с того, что каждый процесс имеет свое ОЗУ (со своим адресным пространством) которое вообще не видно из других процессов. (Конечно такое утверждение спорное. Линии Widows 95...Me и NT...XP очень сильно различались именно в подходе к разделению памяти, а что нам преподнесет Windows.NET пока вообще никто не знает. Но тем не менее все эти операционные системы всегда стремились именно к такому идеалу.) Тогда возникает вопрос о том, как тогда организовывать взаимодействие программы и операционной системы и программ между собой. Для этого создавались так называемые переходники. Переходник представляет собой специальную программу, которая выполняется в одном из процессов операционной системы, но точки входа в сегменты этой программы открыты для других процессов (или всех или только избранных, что в свою очередь определяется на уровне политики безопасности операционной системы). Сам переходник снаружи выглядит как обычная API функция, которой может воспользоваться некоторая программа. Более высокоуровневые интерфейсы такие как COM, DDE и OLE тоже использовали именно этот принцип. Просто их API уровень был глубоко закопан и программист работая с интерфейсом его просто не замечал. Что касается Си-подобных языков, то интерфейс API для них вообще как родной.

Теперь о тех подходах которые нам проповедует VSN. Переходники остались. Но работают они совсем по другому. Теперь вызов самых обычных функций API осуществляется через переходники которые создаются в CLR по указанию программы исполняемой в этой среде. Имеется мнение (а время подтвердит или опровергнет это мнение), что все перечисленные мной интерфейсы начинают уходить в небытие. API интерфейс будет заменен через несколько версий Windows на что-то совсем другое. Теперь о том, как повлияют указанные изменения на подходы в программировании. На уровне простых приложений вообще никак. Переходники создаются автоматически и программисту заботиться об этом не надо (за исключением четкого понимания работы нескольких очень важных атрибутов). Однако люди уже набившие руку на написании сложных многозадачных приложений сразу почувствуют себя не в своей тарелке. У них будет очень много вопросов ответов на которые пока нет.

Изменения в среде выполнения.

Даже нет смысла рассказывать как работали обычные программы в среде Windows, потому что Net программы работают в этой среде абсолютно по другому. С точки зрения операционной системы, программой является сам CLR. Все обращения к интерфейсу API Windows производятся из CLR. И сообщения окну, Windows направляет в CLRCLR транслирует их в выполняемую Net-программу). Взаимодействие выполняемых Net-программ между собой производится через переходники в CLR и Windows не принимает участия в этом процессе. Сам собой напрашивается вывод о том, что CLR это виртуальная машина в которой выполняются Net-программы и которая обеспечивает связь программ с операционной системой (которая тоже является виртуальной машиной обеспечивающей связь с железом компьютера). Но хочу сразу предупредить что я сейчас озвучил очень крамольную мысль - нигде в документации CLR не назван виртуальной машиной, это просто среда выполнения реализованная на уровне классов CLR.

Вот еще один очень интересный факт. Очень большим достижением VSN сегодня называется то, что изменения вносимые Майкрософт в CLR не будут влиять на работу написанных Net-программ. Как это будет достигаться. В среде операционной системы можно будет запускать несколько версий CLR одновременно. А Net-программы будут запускаться в свою очередь в той версии CLR, которая для них подходит. Но я из этого «достижения» сделал для себя два очень печальных вывода. Первое. В CLR будут вносится изменения (и возможно достаточно часто). А это в свою очередь потребует от программистов постоянного доучивания до новых особенностей и усложнит создание новых версий разрабатываемого программного продукта (придется подрехтовывать уже написанный код). И второе. В дистрибутив программ придется включать CLR (надежды на то, что CLR войдет в состав последующих версий Windows таят как снег весной - он может и войдет, но его версия будет совсем не той).

В этой связи тоже есть мнение (абсолютно ничем не подтвержденное). В очень далеком будущем CLR станет ядром операционной системы, а Windows (в современном смысле этого слова) или вообще исчезнет, или будет в составе операционной системы на уровне виртуальной машины запускаемой по требованию (ну так как сейчас DOS в среде Windows). Если дело движется именно к такому, то я всеми четырьмя конечностями «за». Плохо другое. Этот переход (если он конечно идет вообще) будет растянут на много и много лет. Нет большего горя чем жить в эпоху постоянно действующей революции.

Изменения в реализации наследования.

Наследование является сервисом, предоставляемым программисту со стороны языка высокого уровня. То есть, наследование это функциональность (или возможность) языка. Принято считать, что механизм воплощения функциональности в жизнь не должен волновать программиста. Но это чисто формальный подход к вопросу. Когда пишешь действующую программу, неизбежно начинаешь задумываться о том, почему программа работает именно так и не как по другому. И понимание механизмов реализации очень сильно помогает в этих размышлениях. Именно поэтому я хочу поговорить о изменениях в реализации наследования.

В Си-подобных языках реализация наследования производилась на уровне препроцессора (хотя наследование было именно функцией языка а не директивой препроцессору). Все наследуемые классы были доступны на уровне исходных текстов. При запуске программы на компилирование, первым включался в работу именно препроцессор (по сути это автоматический текстовый редактор). Когда он находил наследование, он отыскивал исходный текст наследуемого класса и копировал его в точку наследования. Если требовалось перегрузить член класса, исходный текст члена класса удалялся, а вместо него подставлялся другой. Таким образом собирался полный текст программы, который затем передавался компилятору.

Теперь все работает совсем по другому. Все классы в библиотеке .NET Framework содержаться в уже откомпилированном виде и процесс наследования реализован после прохода по программе первым компилятором. К сожалению я не могу рассказать о «современном» подходе к наследованию более подробно. На сегодняшний день у меня самого больше вопросов чем ответов. Ну чисто по приколу, могу сформулировать свои чувства так: если я уже сижу один раз не в своей тарелке (в связи с изменениями во взаимодействиях процессов), то теперь меня накрыли второй такой тарелкой сверху, и чувствую я себя в них как полный инопланетянин.

Могу добавить к этому еще несколько слов. Программы написанные на С++ всегда можно было откомпилировать в один EXE файл. Над VB6-программами всегда смеялись за то, что они были обязаны тягать за собой целый ворох DLL. Теперь все программы написанные на VSN (вне зависимости от языка) будут тягать за собой CLR.

Еще раз о CLR.

Я получил достаточно много замечаний от читателей по поводу формулировки «размер CLR может составлять несколько сот мегабайт» приведенной мной в предыдущей статье. Как я понял, некоторые читатели уже написали программы на VSN (возможно не очень сложные) и попробовали изготовить дистрибутивы к ним. Мне было написано о том, что размер CLR колеблется в них где-то в пределах от 20 до 30 Мб. Я сообщаю и эту цифру, но при этом указываю, что я не ставлю под этой цифрой своей подписи - это просто некоторая информация полученная рядом читателей путем эксперимента. Дальше я хочу высказать несколько своих соображений по этому поводу и при этом подчеркиваю, это только мои мысли вслух. Каждый из читателей имеет полное право с этим не согласится (в принципе это касается абсолютно всего что написано в моих статьях).

Вначале более подробно о том, что входит в CLR включаемый в дистрибутив программы. Это конечно второй компилятор. И это конечно те классы из библиотеки .NET Framework, которые использованы в программе. А вот эта величина и есть переменной. Когда программа маленькая и классов мало. А если программа очень большая, а если в ней использованы вообще все классы, а если там вдруг окажутся классы процессора базы данных в NET-исполнении (их нет пока, пока у Майкрософт руки до этого не дошли). Вот исходя из всех этих «если» размер CLR в дистрибутиве и будет плавать в очень широких пределах.

Вообще, как по мне, конкретная цифра выраженная в мегабайтах в данном случае не актуальна. Важен её порядок. В самом облегченном виде это пара десятков мегабайт, а в самом радикальном, значительно больше. Были и такие возражения: «на CD-R вполне можно переносить подобные размеры - так какие тогда проблемы?». А проблем с CD-ROM нет абсолютно никаких (разве я это говорил?). Проблемы будут с распространением через Интернет, то есть с тем, ради чего вся эта каша с NET технологией и заваривалась.

Некоторые особенности MSDN.

В целом, у меня сложилось очень приятное впечатление о MSDN. Я просто хочу рассказать о тех особенностях VBN, размышлять над которыми я начал именно после изучения MSDN.

Практически в каждой статье, посвященной описанию функциональности класса или члена класса, имеется раздел «Requirements». В этом разделе приводится список операционных систем в которых можно применять описываемый в текущей статье элемент. Наличие такого раздела меня наводит на очень грустные размышления. Я вспоминаю подобные разделы из секции по описанию функций API. Каждая сборка Windows (и это не секрет) обладает своим набором API. И это очень существенно осложняет жизнь программистам использующим вызовы функций в своих программах. Каждая такая программа начинается с проверки версии операционной системы, а дальше следуют условные блоки декларирования допустимых функций. Но это еще не все. Компилирование программы не дает ответа на вопрос о том, правильно или нет такое декларирование было выполнено. Ответ может быть получен только на этапе тестирования готовой программы, причем тестировать надо под всеми версиями операционки, под которыми программа должна работать. Применительно к VB6, можно было как правило обходится без использования API функций. COM-объекты поставляемые Майкрософт и использующие API в своей работе, делали всегда все безошибочно. И программисты VB6 в прямом смысле этого слова просто обнаглели. Писали программу под одной версией операционки. Потом несли программу заказчику, ставили на совсем другую версию, включали и всегда все работало. Теперь эти времена прошли.

Нам придется осваивать совсем новые подходы в работе. При использовании классов (а без этого совсем не обойтись) из поставляемых библиотек, необходимо постоянно думать о версиях операционки. Но просто думать мало (разве можно дать гарантию что в MSDN нет ошибки). Поэтому надо тестировать и под разными версиями, а это очень большой кусок работы. И еще. Все мы знаем, что скоро выйдет Windows.NET. В принципе, интуитивно понятно, что скорее всего все элементы библиотек будут поддерживаться в этой версии Windows. Но ведь в текущей версии MSDN про это ничего не сказано. А это означает только одно. Сразу за Windows.NET выйдет новая версия MSDN. И я даже думать боюсь о том, что опять все перевернется.

Очень часто, при открытии статьи описывающей функциональность члена класса, можно встретить «описание» такого содержания: «This member supports the .NET Framework infrastructure and is not intended to be used directly from your code». Дословно это переводится так: «Этот член поддерживает .NET Framework инфраструктуру и не предназначен, чтобы использоваться непосредственно в вашем коде». А если не дословно. Мне видится такая картинка. На этапе конечного тестирования VSN вылезла целая куча проблем. Времени на исправление ошибок не было, поэтому глючащие члены классов попросту заблокировали и покрыли сие безобразие туманной фразой в MSDN. И опять в мою голову лезут очень грустные размышления. При написании программы надо постоянно отслеживать заблокированные члены классов (а они наследуются и пере наследуются). И где гарантия что уже все глюки заблокированы и что не свалятся они на мои хрупкие плечи.

Анализ почты.

За пол года, прошедших после опубликования вторых впечатлений, я получил около 250 писем. Как я и обещал, я не вступал в переписку (ну пара, тройка исключений все-таки была, когда письма меня действительно заинтриговали). Именно поэтому я хочу сейчас постараться ответить на те вопросы, которые задавали наиболее часто.

Вначале общий счет. Он примерно такой. 80% читателей с самым большим энтузиазмом или готовы встретить, или уже встретили новую NET-технологию. Примерно 15%, увидели в моих статьях призыв строить баррикады и идти на войну против Майкрософт. И только 5% (именно к этой категории я отношу сам себя) начали осваивать новую технологию не торопясь и основательно (хотя и очень громко чертыхаясь при этом).

Самая большая категория писем принадлежит ВОЗМУЩЕННЫМ (вот уж совсем не думал) читателям так гордо владеющим дармовыми почтовыми ящиками. Давайте разберемся с этой ситуацией. В принципе, я (как и все нормальные люди) не делю людей написавших мне письмо по «расовому признаку». Я читаю абсолютно все письма пришедшие на адрес указанный ниже этой статьи (я сам создал этот почтовый ящик специально для почты связанной с моими публикациями). И когда я читаю письмо, я не могу знать с какого майла оно было направлено. Совсем другое дело, когда письмо явно провокационное или грубое. Моей естественной реакцией является попытка определить источник происхождения письма. И вот тут и появляются эти самые закономерности. Все письма подобного содержания написаны именно с дарммайлов. И коль скоро я заговорил на эту тему, я хочу рассказать еще кое что. В должностные обязанности сетевых администраторов на серьезных фирмах входит ограждение сотрудников фирмы от получения писем с дарммайлов. Солидные провайдеры Интернет могут обеспечить эту услугу как дополнительный сервис. Любой пользователь Интернет может установить на свой почтовый клиент базу дарммайлов для фильтрации входящей почты. Для чего все это делается? - Очень простая логика. Человек написавший письмо с такого почтового ящика явно имеет основания скрывать свое местонахождение, а значит его намерения скорее всего или враждебные, или даже несут потенциальную угрозу (вирусы например). Подумайте как-нибудь на досуге над таким вопросом: почему не было ответа на посланное Вами резюме? - может быть потому что его вообще никто и не читал.

Теперь о ошибках орфографических и грамматических в моих статьях. Где-то в глубине своей души, я являюсь истинным борцом за чистоту рядов русского языка. Но жизнь все расставляет по другому. Когда на написание статьи попросту не хватает времени и тем более его совсем нет на дотошное перечитывание и исправление, возникают всякого рода накладки и недоразумения. И вот Вам еще одна интересная закономерность. Люди которые отнеслись к моим статьям как к полезной информации, моих ошибок вроде как и не заметили. Но была совсем другая категория читателей. От них приходили письма примерно такого содержания: «Прочитал твою статью. Да ты попросту полный идиот. И почему ты так безграмотно пишешь...»; а дальше следовал полный разбор всех моих ошибок (одно письмо было даже длиннее чем вторая статья - просто супер). Но есть в этом деле один интересный курьез. Всю свою далеко не праведную жизнь я пользовался словом «сайт» исключительно в разговорной речи. Как на мой взгляд, это сленг пришедший к нам из английского языка. Использовав это слово во второй статье, я запустил проверщик орфографии из Word-2000. Результат меня ошарашил. Мне было предложено заменить «сайт» на «сайд»... И я занялся журналистским расследованием. Чем глубже я копал, тем больше болела моя голова. Например, в базе данных слов русского языка (версия за июнь 2001г.) действительно имеется «сайд» и отсутствует «сайт». К сожалению база данных не отвечает на вопрос о значении слова (ведь это вполне может быть какой-нибудь микробиологический термин). Короче говоря, хотите верьте а хотите нет, я подбросил монетку (единственно верное решение), а результат Вы уже читали. Кстати, Word-XP вполне нормально относится к обоим словам. Но вопроса это не снимает. Если меня кто-нибудь спросит о том как все-таки следует писать, я не буду знать что ответить этому человеку.

Очень большая группа читателей, уловив мои недовольства связанные с изменениями в архитектуре Windows, пыталась меня совратить к сожительству с другими операционными системами (такими как Linux например) или с другими языками программирования (такими как Java). Но тем не менее я не совратился. Вообще говоря, к другим операционным платформам я отношусь очень плохо. Я исхожу не из принципа «программирование во имя любви к искусству». Я практик и пишу программы только под те платформы, под которые их заказывают. Когда в офисах на компах будут появляться другие операционки (и это явление станет массовым) я обязательно пересмотрю свои взгляды. Но пока говорить об этом сильно преждевременно. Совсем другое дело языки программирования. Но тут надо иметь ввиду одно очень важное обстоятельство. Изменения в архитектуре Windows потянут за собой изменения во всех языках программирования ориентированных на эту платформу. Поэтому решения надо принимать очень обдуманно и осторожно.

P.S. Возможно я очень много говорю о недостатках NET и сильно мало о её достоинствах. О достоинствах сейчас пишут все. Но жить и работать нам приходится именно с недостатками.

Написано для vbnet.ru

23.01.2003 г.

Гриненко Виталий

gwii@svitonline.com

 
     

   
   
     
  VBNet рекомендует