HQLA. Выпуск #4

Категории: hqla
Тэги: , ,

В этом выпуске:
Раздел: Средний .NET разработчик

  1. Вопрос #10: Опишите разницу между интерфейсно-ориентированным, объектно-ориентированным и аспектно-ориентированным стилями программирования.
  2. Вопрос #11: Дайте описание Интерфейса и опишите основные его отличия от Класса.
  3. Вопрос #12: Что такое Reflection?

Вопрос #10: Опишите разницу между интерфейсно-ориентированным, объектно-ориентированным и аспектно-ориентированным стилями программирования.

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

Вопрос #11: Дайте описание Интерфейса и опишите его основные отличия от Класса.

Ответ: Ответ на этот вопрос чрезвычайно объемен. Попробую сделать выжимку. Начать, думаю, стоит с определений, доступных в спецификации языка C#:
Класс – структура данных, которая может содержать: члены-данные, такие как константы и переменные; члены-функции, такие как методы, свойства, события, индексаторы, операторы, конструкторы класса, деструкторы и статические конструкторы; вложенные типы. Классы поддерживают одиночное наследование.
Интерфейс – структура данных, которая может содержать: методы, свойства, события и индексаторы. Интерфейс не содержит реализации этих типов. Он определяет контракт, предписывающий, классам и структурам, которые реализуют этот интерфейс реализовывать все его члены. Интерфейсы поддерживают множественное наследование.
Уже из определения видно, что основное различие – идеологическое. Не смотря на то, что с точки зрения CLR и то и то является типом данных, класс – это контейнер, а интерфейс – контракт.
Вообще говоря, вопрос, поставленный в самом начале не совсем верен. О различиях, как мне кажется, мы можем говорить, в случае сущностей противоположных или в каких-то аспектах, претендующих на одну и ту же роль. Такая ситуация имеет место быть, например, в случаях с абстрактными классами и интерфейсами. В обобщенном же случае мы говорим и связке «класс-интерфейс», эффективно они существуют в паре. Отсутствие механизма множественного наследования в CLR в большинстве случаев разрешается множественной реализацией интерфейсов. В случае значимых типов, когда имеется базовый тип ValueType, наличие интерфейсов позволяет создавать пользовательские типы, удовлетворяющие определенным ограничениям и т.п.

Вопрос #12: Что такое Reflection?

Ответ: Говоря формально, Reflection или Отражение (перевод, принятый в русскоязычной литературе), по сути, процесс, при котором приложение во время выполнения, может отслеживать трассу исполнения, поведение и собственную структуру и менять их. В разрезе .NET, а мы говорим, уже о конкретной реализации отражений в среде виртуальной машины .NET, этот механизм реализован с помощью средств, доступных в пространстве имен System.Reflection. Эти средства позволяют читать метаданные сборок, подгружать их в домены приложений, исполнять методы и использовать типы сторонних сборок, о которых приложение в момент компиляции ничего не знает. Чаще всего, практическое применение механизм отражений находит в создании приложений, поддерживающих подключаемые модули (add-in). Однако наличие механизмов отражений открывает широкие возможности для метапрограммирования и создания суперкомпиляторов.

Пояснения к вопросу #6 HQLA

Категории: hqla
Тэги: ,

На шестой вопрос ответов на вопросы Хансельмана, по поводу Component Cоntainer, пришло некоторое количество недоуменных отзывов. Действительно, я написал несколько расплывчато и не объяснил откуда взялся именно Windows Server. Попробую исправиться.

В данном вопросе речь идет скорее о поддержке разноцелевых операционных систем. Серверные опреационные системы несколько отличаются от клиентских. Разный набор поддерживаемых фич. Дело в том, что в .NET CL есть множество Component Container, однако в МСДН, в разделе про применимость каждого из них, частенько ничего не сказано о поддержке серверных ОС. Ограничения могут быть связаны, например, с тем, что серверные ОС не поддерживают красивостей интефейсной части, там нет тем рабочего стола, потому большая часть контролов относящихся к украшательству на сервере недоступна, и т.п.

Мне кажется, что правильнее было бы сформулировать вопрос о наиболее универсальных Compnent Container, применимых как в серверных так и в клиентских ОС.

HQLA. Выпуск #3

Категории: hqla
Тэги: , ,

В этом выпуске:
Раздел: Каждый, кто пишет код

1. Вопрос #7: Что такое PID? Как его можно использовать для устранения неисправностей системы?
2. Вопрос #8: Сколько процессов могут “слушать” один TCP/IP порт?
3. Вопрос #9: Что такое GAC? Какую проблему он решает?

Вопрос #7: Что такое PID? Как его можно использовать для устранения неисправностей системы?
Ответ: PID (Process Identifier) уникальный идентификатор процесса, который выдается системой при создании. Идентификатор интересующего процесса можно подсмотреть в Task Manager. Использовать идентификатор процесса можно для завершения этого процесса из Task Manager, можно подключать к нему из дебугер Visual Studio при наличии соответствующих символов и т.д. Подробнее о процессах можно почитать в ответе на первый вопрос и по ссылке на MSDN.

Вопрос #8: Сколько процессов могут “слушать” один TCP/IP порт?
Ответ: В каждый момент времени только один.

Вопрос #9: Что такое GAC? Какую проблему он решает?
Ответ: GAC (Global Assembly Cache) – кэш для хранения сборок .NET. По сути GAC – это директория расположенная по пути %WINDIR%\assembly и хранящая все зарегистрированные сборки. Хорошим тоном считается, при использовании сборки на клиентской машине, зарегистрировать её в GAC. Это помогает решить, так называемую проблему dll-hell. GAC позволяет отслеживать версионность, связи и зависимости сборок (динамически линкуемых библиотек, к примеру) зарегистрированных в системе, тем самым избавляя разработчика от множества проблем связанных с подгрузкорй «не той» dll, выщитыванием и валидацией пути к нужной dll и т.п. (http://msdn.microsoft.com/en-us/library/yf1d93sz.aspx)

HQLA. Выпуск #2

Категории: hqla
Тэги: , ,

В этом выпуске:
Раздел: Каждый кто пишет код.

  1. Вопрос #4: Какая разница между исполняемым EXE-фалом и библиотекой динамической линковки DLL?
  2. Вопрос #5: Чем строгая типизация отличается от нестрогой типизации? Какая предпочтительнее? Почему?
  3. Вопрос #6: Некий продукт является “Component Container”. Назовите хотя бы 3 компонента семейства Windows Server которые можно называть “Component Container”.

Вопрос #4: Какая разница между исполняемым EXE-фалом и библиотекой динамической линковки DLL?
Овтет: Оговорюсь сразу, основные различия между exe и dll буду рассматривать в рамках .NET. Для начала расшифруем названия, дабы было все ясно: exe-сокращение от executable, т.е. исполняемый файл; dll – сокращение от dynamic linked library, т.е. динамически линкуемая библиотека. Получается, что exe мы выполняем и в процессе используем некие методы или типы из динамической библиотеки. С точки зрения кодирования в случае исполняемого фала необходимо наличие единственной “точки входа”. В коде это реализуется обязательным public static методом Main, который в качестве параметров, например, может брать массив строк, содержащий параметры командной строки. При создании динамической библиотеки, мы вообще можем не задумываться о “точке входа”. По сути это просто набор классов, интерфейсов, структур и т.п. необходимых нам для структурирования ПО. С точки зрения внутренней структуры файла, то исполняемый файл от библиотеки можно отличить например по PE-заголовку.

Вопрос #5: Чем строгая типизация отличается от нестрогой типизации? Какая предпочтительнее? Почему?
Ответ: Для начала рассмотрим основные различия между сильной и слабой типизацией. Прежде всего, слабая типизация предполагает неявное вычисление/преобразование типов и/или ad hoc (это слово я сам не рискую переводить и толкового перевода ещё не встречал) полиморфизм. При сильной или строгой типизации все типы известны заранее, и преобразование проходит по заранее установленным строгим правилам. Строгим, понятно, по отношению к правилам принятым при слабой типизации. Классическим примером слабой типизации является, например, присвоение значения переменной в языке TCL. С одной стороны мы можем написать:

set myVal "Hello world!"

myVal – строка

с другой стороны можно написать так:

set myVal [file dirname [file dirname $curentdir]]

maVal – путь

Или, делая так:

set myVal {}

А потом в цикле так:

lappend myVal @someItem

в myVal получим список.

Таким образом, тип переменной вычисляется на момент выполнения присвоения ей некого значения.

Сильную (строгую) типизацию, представляет язык C#. Если раньше в C++ мы могли написать:

MyObj* m_pObj = GenerateMyObj();
if(!m_pObj)
    return -1;

То уже в C# такое преобразование типов не пройдёт, тут будь добр делать все явно:

MyObj m_pObj = GenerateMyObj();
if(m_pObj == null)
    return -1;

В этой разновидности типизации для присвоения переменной некоторого значения мы должны сначала объявить эту переменную и задать ей тип. Т.е. основное отличие от слабой типизации в том, что на момент компиляции все типы должны быть известны. Так же, не может быть речи не о каком ad hoc полиморфизме. Например в случае функционального полиморфизма операция сложения, определённая для целочисленных типов, при использовании со строками просто вызовет ошибку компиляции.
На вопрос что лучше, понятно, однозначный ответ получить сложно. Мне по духу ближе сильная динамическая типизация, однако и в слабой есть свои плюсы, язык с такой системой типов более гибкий. Однако у строгой типизации, как мне кажется, есть одно неоспоримое преимущество, такой код чаще, банально, надёжнее. Использование операторов кастования as или is в C#, сводит появления исключительной ситуации практически на нуль. Однако речь идёт о компилируемых языках, для интерпретируемых слабая типизация оказывается удобнее и прозрачнее.

Вопрос #6: Некий продукт является “Component Container”. Назовите хотя бы 3 компонента семейства Windows Server которые можно называть “Component Container”.
Ответ: Начнём со строгих определений в рамках .NET. Контейнером называется объект, реализующий интерфейс System.ComponentModel.IСontainer или наследующийся от класса реализующего этот интерфейс, и, содержащий нуль или более компонентов. В свою очередь, компонентом называется объект, реализующий интерфейс Systerm.ComponentModel.IСomponent или наследующийся от класса, реализующего этот интерфейс, предназначенный для повторного использования и взаимодействия с другими объектами.
Самое важное, это то, что компонентом является объект, который мы можем повторно использовать. Воплощение идеи объектно-ориентированного программирования. Зачем нам писать что-то свое, когда мы можем использовать уже написанный, оттестированный и отлаженный компонент? По сути, реализации интерфейсов IComponent и IContainer необходимы для более грамотного и удобного обращения с компонентами. Любой графический контрол тоже компонент, который описывает пользовательский интерфейс. Т.е .компонент с визуальным представлением.
Что же касается примеров, возьмем основные контейнеры: System.Windows.Forms.Form, System.Windows.Forms.UserControl и, например, System.Windows.Forms.PrpertyGrid.

HQLA. Выпуск #1.

Категории: hqla
Тэги: , ,

Первый выпуск ответов на вопросы HQLA.

В этом выпуске:

Раздел: Каждый кто пишет код.

  1. Вопрос #1: Опишите разницу между Нитью и Процессом.
  2. Вопрос #2: Что такое Сервис Windows и чем его жизненный цикл отличается от жизненного цикла обычного EXE файла?
  3. Вопрос #3: Каков максимальный объем памяти адресуемой одним процессом в Windows? Отличается ли этот объем от общего объема виртуальной памяти выделяемой системой? Как это отражается на архитектуре системы?

Вопрос #1: Опишите разницу между Нитью и Процессом.

Ответ: По сути основная разница в том, что нить и процесс в данном случае сущности разного уровня абстракции. Начнем сверху. Исполняемый модуль состоит из процессов, одного или нескольких. Грубо говоря процесс – суть выполняемая программа. Каждый процесс состоит из одной или нескольких нитей. Нить же – последовательность команд непосредственно под которую система выделяет процессорное время. Однако, как мне кажется, основная цель данного вопроса завести разговор о ресурсах.

Процесс имеет в своем распоряжении ресурсы необходимые для выполнения программы: виртуальное адресное пространство, исполняемый код, открытые указатели на системные объекты, набор настроек и атрибутов безопасности, уникальный идентификатор, переменные окружения, приоритеты классов, максимальный и минимальный размер области, в которой происходит исполнение процесса и как минимум одну нить для исполнения. Каждый процесс стартует с нити, называемой начальной, и далее в процессе исполнения может порождать дополнительные нити.

Нить – внутренняя сущность процесса, которая может быть выполнена в соответствии с некоторым расписанием или событием. Все нити процесса разделяют его виртуальное адресное пространство и системные ресурсы. Но у нити есть и собственное окружение, которое включает обработку исключительных ситуаций, приоритет исполнения, локальная область памяти (TLS), уникальный идентификатор нити и набор сущностей, хранящих ее контекст во время ожидания исполнения. Контекст нити включает значения машинных регистров, используемых нитью, стеки как системный так и пользовательский, и переменные окружения. Так же нить может иметь свой контекст безопасности для обезличенных (в плане принадлежности пользователю) клиентов.(http://msdn2.microsoft.com/en-us/library/ms681917(VS.85).aspx)

Вопрос #2: Что такое Сервис Windows и чем его жизненный цикл отличается от жизненного цикла обычного EXE файла?

Ответ: Под Сервисом Windows понимается приложение, реализующее программный интерфейс для управления посредством Диспетчера Управления Сервисами (Service Control Manager, SCM). Существует несколько способов запуска сервисов: автоматически при старте операционной системы, с помощью Диспетчера Управления Сервисами, программно, вызывая функции, описанные в интерфейсе Сервиса.

Одна из основных особенностей жизненного цикла Сервиса, отличающего его от обыкновенного EXE файла состоит в том, что он может работать при отсутствии инициированной пользовательской сессии локальной или удаленной консоли. Про функции которые должен реализовывать сервис подробнее можно почитать тут (http://msdn2.microsoft.com/en-us/library/ms685942.aspx).

Вопрос #3: Каков максимальный объем памяти адресуемой одним процессом в Windows? Отличается ли этот объем от общего объема виртуальной памяти выделяемой системой? Как это отражается на архитектуре системы?

Ответ: Виртуальная память в Windows имеет плоскую страничную архитектуру, операционная система создает процессам иллюзию того, что он работают в закрытом адресном пространстве. Логическая организация страниц памяти, вообще говоря, может не соответствовать физической организации памяти. Отображение или мэпирование адресов логического представления в адреса физического происходят на аппаратном уровне силами диспетчера памяти. Объем физической памяти зачастую отличается, в меньшую сторону, от объема виртуальной памяти и для обеспечения хранения всех страниц виртуальной памяти системой используется механизм подкачки. Суть механизма состоит в том, что мало используемые страницы выгружаются из оперативной памяти на диск, а при необходимости обращения к данным записанным на диск, требуемая виртуальная страница подкачивается обратно в оперативную память.

Далее я приведу небольшую таблицу, описывающую размер виртуального адресного пространства выделяемого одному процессу, в зависимости от архитектуры системы:

Архитектура Размер виртуального адресного пространства
x86 Всего 4 GB из них 2 GB системе 2 GB процессу
x86 со спец. ключами /3GB и /USERVA d boot.ini для ос Win2K (Server/Client), Win2K3, WinXP Всего 4 GB из них 1 GB системе 3 GB процессу
x86 с системой Address Windowing Extension Всего 64 Gb но используется механизм проецирования на 2Gb виртуальное адресное пространство.
x64 В связи с реализационными ограничениями 6657 GB системе и 8192 GB процессу. Адресное пространство меньше теоретически возможного.
Itanium В связи с реализационными ограничениями 6144 GB системе и 7152 GB процессу. Адресное пространство меньше теоретически возможного.

(http://msdn2.microsoft.com/en-us/library/aa366912.aspx)