C# — Помогите пожалуйста. Программа с# не работает


Содержание

Отладка кода

В C#, как и в других появившихся до .NET языках, главная методика по отладке состоит в добавлении точек останова и изучении того, что происходит в коде в конкретные моменты во время его выполнения.

Точки останова

Точку останова (breakpoint) в Visual Studio можно помещать на любую строку кода, которая в действительности выполняется. Самый простой способ — щелчок на необходимой строке в окне редактора кода внутри затененной области вдоль левого края окна документа (или выделение нужной строки и нажатие клавиши ). Это приводит к размещению в данной строке точки останова, которая вызывает прерывание процесса выполнения и передачу управления отладчику. Как и в предыдущих версиях Visual Studio, точка останова обозначается большим кружком слева от соответствующей строки в окне редактора кода. Кроме того, Visual Studio выделяет саму строку, отображая ее текст и фон разными цветами. Щелчок на кружке приводит к удалению точки останова.

Если останов на определенной строке каждый раз не подходит для решения имеющейся проблемы, можно создать так называемую условную точку останова. Для этого выберите в меню Debug (Отладка) пункт Windows — Breakpoints (Окнo — Точки останова). Откроется диалоговое окно, позволяющее указать желаемые детали для точки останова. В этом окне можно выполнять следующие действия:

Указать, что выполнение должно прерываться лишь после прохождения точки останова определенное количество раз.

Указать, что точка останова должна вступать в действие при каждом n-ном достижении строки, например, при каждом 20-м ее выполнении (это удобно при отладке больших циклов).

Задать точки останова относительно переменных, а не команд. В таком случае наблюдение будет вестись за значением указанной переменной, и точки останова будут активизироваться при каждом изменении значения этой переменной. Однако этот вариант может сильно замедлить выполнение кода, поскольку на проверку, не изменилось ли значение отслеживаемой переменной после выполнения каждой очередной инструкции, будет тратиться дополнительное время процессора.

Слежения

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

Для просмотра значений переменных можно также использовать окно Autos (Автоматические). Окно Autos представляет собой окно с вкладками, которое появляется лишь тогда, когда программа выполняется в режиме отладки. Если вы его не видите, попробуйте выбрать в меню Debug (Отладка) пункт Windows — Autos (Окна — Автоматические).

В этом окне рядом с переменными, которые являются классами или структурами, отображается пиктограмма с изображением знака «плюс», щелчок на которой позволяет развернуть представление переменной и просмотреть значения ее полей.

Три предлагаемых в этом окне вкладки предназначены для наблюдения за переменными трех разных категорий:

Вкладка Autos (Автоматические) позволяет просматривать значения нескольких последних переменных, к которым осуществлялся доступ в процессе выполнения программы.

Вкладка Locals (Локальные) позволяет просматривать значения переменных, к которым получается доступ в методе, выполняемом в текущий момент

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

Исключения

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

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

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

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

На самом деле в Visual Studio предлагается очень действенное решение. Если заглянуть в меню Debug (Отладка), то можно будет обнаружить там пункт Exceptions (Исключения). В случае выбора этого пункта открывается диалоговое окно Exceptions (Исключения). Это окно позволяет указывать, что должно происходить при выдаче исключения. Здесь можно указать, что выполнение должно продолжаться или же останавливаться с переходом в режим отладки, в случае чего произойдет останов, а отладчик окажется прямо на самом операторе throw:

Visual Studio известно обо всех классах исключений, которые доступны в базовых классах .NET, и о многих таких исключениях, которых могут выдаваться за пределами среды .NET. Распознавать автоматически специальные классы исключений, создаваемые разработчиками, Visual Studio не умеет, но позволяет вручную добавлять такие классы исключений в список и, следовательно, указывать, какие из таких исключений должны приводить к немедленному прекращению выполнения приложения. Для этого необходимо щелкнуть на кнопке Add (Добавить), которая активизируется при выборе самого верхнего узла в дереве, и ввести имя специального класса исключения.

Дополнительные команды отладки исходного кода

Компиляция практически всего коммерческого программного обеспечения на стадии отладки и на стадии подготовки окончательной версии продукта должна проводиться немного по-разному. Среда Visual Studio способна понимать это, поскольку сохраняет информацию обо всех параметрах, которые ей надлежит передавать компилятору. Для поддержки разных вариантов компоновки проекта Visual Studio потребуется сохранять подобную информацию в более чем одном экземпляре. Разные экземпляры такой информации называются конфигурациями. При создании проекта Visual Studio автоматически предлагает на выбор две таких конфигурации, которые называются, соответственно, Debug (Отладка) и Release (Выпуск):

Конфигурация Debug обычно указывает, что никакие операции по оптимизации выполняться не должны, в исполняемом коде должна присутствовать дополнительная отладочная информация, а компилятор должен предполагать, что в коде определен препроцессорный символ отладки Debug, если только он не был явно отменен с помощью директивы #undefined.

Конфигурация Release указывает, что компилятор должен проводить в отношении компилируемого кода оптимизацию, в исполняемом коде не должно присутствовать никакой дополнительной информации, а компилятор не должен предполагать наличие препроцессорного символа Debug.

Можно также определять собственные конфигурации. Это необходимо, например, для компоновки приложения с несколькими отличающимися версиями. Раньше из-за проблем, связанных с поддержкой кодировки Unicode в Windows NT, но не в Windows 95, для многих проектов на С++ было принято создавать две конфигурации — одну для Unicode, а вторую для (multibyte character set — набор многобайтных символов).

Записная книжка программиста-новичка, C#, SQL, PHP и все-все-все

Я ведь это уже делал, но хрен теперь найдешь тот кусок кода, гуглим снова… Где бы найти простое и понятное руководство для начинающего, а не тонкости для мега-гуру?

Рубрики

Свежие записи

Свежие комментарии

  • Calator prin Romania к записи Как переименовать проект/каталог проекта в Visual Studio?
  • iukovl к записи Как изменить максимальный размер загружаемого файла в php
  • sdfdsgeg к записи Работа с файлом конфигурации (configuration) в C# — читаем и сохраняем
  • iukovl к записи Как изменить максимальный размер загружаемого файла в php
  • Надежда к записи Ошибка в коде привела к убыткам в 476 миллионов долларов и банкротству компании

Архивы

Как запустить другую программу/исполняемый .exe файл из кода C#

Задача: из программы на C# запустить другую программу (исполняемый файл). В теории все просто

Но есть нюанс, если запускаемая программа находится в другом каталоге и использует для получения инофрмации о текущем каталоге функцию Directory.GetCurrentDirectory, то она получит вместо собственного каталога каталог исходной программы, из которой и запускается второй исполняемый файл.

Вылечить это можно двумя способами.

1) Использовать для получения каталога с исполняемым файлом функцию GetCurrentDirectory несколько неправильно, так как ее значение может расходится с каталогом программы, лучше использовать Application.StartupPath.

2) Если надо поддерживать совместимость со старым/чужим кодом или вообще запускать чужой исполняемый файл, мы можем вручную переопределить рабочий каталог запускаемой программы с использованием класса информации о процессе ProcessStartInfo

Комментарии

Как запустить другую программу/исполняемый .exe файл из кода C# — Комментарии (7)

Спасибо за инфу

А возможно запустить exe на Си из программы на C#? Например, запускаем exe на С#, в нем стартует прописанный exe на Си — результат сохранить в .тхт, и прочитать этот .тхт из exe C#. Си(кансоль)\\C#(окна)

Все исполняемые файлы двоичные, на каком бы языке они ни были написаны. Так что разницы не должно быть. По идее попробовать экспериментально выйдет быстрее чем писать вопрос. ))

А как при таком запуске отследить, работает ли запущенное приложение или закончило работу?


Куда писать приложение которое я хочу запустить?

10 фич в C#, о которых вы определённо должны узнать и начать их использовать

Если вы только начали изучение C# или же решили расширить свои знания, мы нашли для вас 10 фич, знание которых позволит вам избежать ошибок, писать более понятный код и сохранить кучу времени.

1. async / await

Использование паттернов async / await позволяет разблокировать UI / текущий поток во время выполнения блочных операторов. Паттерны async / await позволяют коду продолжить выполнение, даже если что-то блокирует его выполнение (например, веб-запрос).

2. Инициализаторы объектов / массивов / коллекций

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

3. Лямбды, предикаты, делегаты и замыкания

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

4. ?? (Оператор объединения с NULL)

x ?? y — возвращает x , если значение отличается от null ; в противном случае возвращает y .

Может быть несколько операторов .

?? также может быть использован для перевода типов null в не null :

5. $”” (Интерполяция строк) — C# 6

Фича в C# 6 позволяет эффективно и элегантно собирать строки:

6. ?.(определяет null) — C# 6

x?.y — доступ к членам, определяемый условием null . Возвращает значение null , если левый операнд имеет значение null .

Больше никаких NullReferenceExceptions!

7. Выражение nameof — C# 6

Может показаться, что выражение nameof не особо полезно, но это не так. При использовании автоматических инструментов рефакторинга (например, ReSharper) иногда может потребоваться обратиться к аргументу метода по его имени:

Вот, как это должно быть:

8. Инициализаторы свойств (property) — C# 6

Инициализаторы свойств позволяют задавать начальные значения для свойств:

Польза их использования заключается в том, что вы не можете объявить setter, тем самым делая свойства неизменяемыми. Инициализаторы свойств хорошо работают в связке с синтаксисом первичного конструктора в C# 6.

9. Операторы as и is

Is — совместимость типов. Возвращает значение true, если вычисленный левый операнд может быть приведен к типу, указанному в правом операнде (статический тип).

As — преобразование типов. Возвращает левый операнд, приведенный к типу, заданному правым операндом (статический тип), но as возвращает null , где (T)x вызывает исключение.

10. Ключевое слово yield

Ключевое слово yield позволяет заполнить интерфейс IEnumerable объектами (items). Следующий пример вернет все степени двойки от 2 до 2 в степени 8 (то есть 2, 4, 8, 16, 32, 128, 256):

В правильных руках yield — очень мощная вещь. Оно позволяет с легкостью генерировать последовательность объектов, то есть системе не придется перечислять всю коллекцию целиком — это может быть сделано по требованию.

Hello, C# — Учим Шарп #2

Опубликовано shwan в 08.11.2020 08.11.2020

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

Перед началом данного урока рекомендую ознакомиться с предыдущим Преимущества и недостатки C# — Учим Шарп #1

Как работает компьютер

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

  • Записать значения в память
  • Прочитать значение из памяти
  • Выполнить операции сложения, умножения, отрицания

И именно так он на самом деле и работает – обрабатывает миллиарды единиц информации каждую секунду, чтобы ты мог погонять в дотку или порнушку посмотреть. Вот такая у компьютера незавидная участь, поэтому не обижай его, заботься о нем. Вот когда ты последний раз чистил его от пыли? А?

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

Что такое языки программирования

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

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

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

Инструмент создания приложений IDE

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

Visual Studio

Так вот, основным инструментом C# программиста является интегрированная среда разработки Visual Studio 2020 на данный момент. Скачать ее можно по ссылке https://visualstudio.microsoft.com/ru/ Существует 3 основные версии

Разница между ними только в количестве всех вот этих наворотов и цене. На начальном этапе я всем рекомендую использовать Community версию, которая является бесплатной с небольшими ограничениями:

— Visual Studio Community может использовать неограниченное число пользователей в учебных аудиториях, для научных исследований или участия в проектах с открытым кодом.

— Для всех прочих сценариев использования: в некорпоративных организациях Visual Studio Community может использовать до 5 пользователей. В корпоративных организациях (в которых используется > 250 ПК или годовой доход которых > 1 млн долларов США) использование запрещено.

Таким образом, пока ты зарабатываешь меньше 1 млн долларов в год, ив твоей команде меньше 5 человек, можешь разрабатывать любое ПО в том числе и коммерческое.


Сейчас установка, обновление и изменение компонентов Visual Studio стало достаточно приятных и простым занятием, хотя раньше приносило достаточно много головной боли. Просто скачивай специальное приложение-установщик на свой компьютер и запускай установку. После скачивания необходимых компонентов, откроется окно выбора того, что тебе нужно установить.

Так как разработка на C# подразумевает универсальные приложения под любые платформы, то предоставляется over9000 компонентов, которые в большинстве своем совершенно тебе не нужны на данном этапе. Сейчас я покажу тебе необходимый минимум, а также мою рекомендуемую коллекцию компонентов.

  • Разработка классических приложений .NET — обязательно
  • ASP.NET и разработка веб-приложений
  • Кроссплатформенная разработка .NET Core

Самые нужные расширения для Visual Studio

После установки Вижуалки также очень рекомендую тебе установить несколько расширений, которые очень сильно помогут тебе работать в дальнейшем.

Для этого открываем меню Средства => Расширения и обновления

Выбрать В сети и в строке поиска ввести названия необходимых расширений

ReSharper – суперкрутой статический анализатор кода. Может практически все, но некоторым (в том числе мне) не нравится, потому что бесит, и является платным. Но в целом очень полезен.

Web Essentials – mast have для веб программистов. Позволяет весьма упростить и ускорить процесс работы в интерфейсной частью приложения, упрощает и ускоряет верстку, но в других случаях он не нужен.

Productivity Power Tools 2020/2020 – целый набор небольших расширения, позволяющих сделать процесс написания кода комфортнее, код чище и красивее. Настоятельно рекомендую устанавливать каждому.

GitHub Extension for Visual Studio – очень удобное взаимодействие с популярным сервисом хранения кода и системой контроля версий. Каждому программисту нужно научиться и постоянно использовать любую подходящую систему контроля версий. А это расширение позволит форкать проекты и выполнять коммиты в пару кликов.

Visual Studio Spell Checker — позволяет избавиться от таких досадных ошибок, как опечатки в коде. Работает примерно как в ворде — подчеркивает красным не правильные слова. При этом он понимает различные нотации и без проблем понимает, что написанные слитно слова, но с заглавными буквами это не ошибка.

Важной функцией Visual Studio является встроенный помощник IntelliSense, который позволяет очень удобно обозревать классы, дополнять названия, показывать подсказки по улучшению кода. Обязательно научись им пользоваться и прислушивайся к его советам.

Создадим Hello World проект на C#

Открываем среду разработки Visual Studio и заходим в меню Файл => Создать => Проект

После этого выбираем Visual C# => Классическое приложение для Windows => Консольное приложение (.NET Framework), вводим имя проекта, указываем его расположение на диске и нажмем ОК.

В открывшимся окне вводим следующий код приложения

После чего запускаем приложение, нажав сочетание клавишь Ctrl+F5 или зеленую клавишу Пуск и получаем следующий результат

Поздравляю, вы создали свое первое приложение!

Подробно, весь процесс установки и настройки Visual Studio, а также создание первого приложения рассмотрен на моем видеоуроке.

Заблуждения начинающих C# разработчиков. Пытаемся ответить на стандартные вопросы

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

#1. Мантра про 3 поколения в любой ситуации

Это скорее неточность, чем заблуждение. Вопрос про «сборщик мусора в C#» для разработчика стал классикой и уже мало кто не начнет на него бойко отвечать про концепцию поколений. Однако, почему-то, мало кто обращает внимание на то, что великий и ужасный сборщик мусора — часть рантайма. Соответственно, я бы дал понять, что не пальцем пихан, и спросил бы про какую среду исполнения идет речь. По запросу «сборщик мусора в c#» в интернетах можно найти более, чем много похожих сведений. Однако мало кто упоминает, что данная информация относится к CLR/CoreCLR (как правило). Но не стоит забывать и про Mono, легковесный, гибкий и встраиваемый рантайм, который занял свою нишу в мобильной разработке (Unity, Xamarin) и используется в Blazor. И для соответствующих разработчиков я бы посоветовал поинтересоваться подробностями устройства сборщика в Mono. Например, по запросу «mono garbage collector generations», можно увидеть, что поколения всего два — nursery и old generation (в новеньком и модном сборщике мусора — SGen).

#2. Мантра про 2 стадии сборки мусора в любой ситуации

Еще не так давно исходники сборщика мусора были скрыты от всех. Однако интерес к внутреннему устройству платформы был всегда. Поэтому информация извлекалась разными путями. И некоторые неточности при реверс-инжиниринге сборщика привели к мифу о том, что сборщик работает в 2 стадии: маркировка и чистка. Или и того хуже, 3 стадии — маркировка, чистка, сжатие.

Однако все изменилось, когда народ огня развязал войну с появлением CoreCLR и исходников сборщика. Код сборщика для CoreCLR был целиком взят из CLR версии. Никто с нуля его не писал, соответственно, почти все, что можно узнать из исходников CoreCLR, будет верно и для CLR. Теперь, чтобы понять, как что-то работает, достаточно зайти на github и найти это в исходном коде или прочитать readme. Там же можно увидеть, что существует 5 фаз: маркировки, планирования, обновления ссылок, компактинга (удаление с перемещением) и удаление без перемещений(перевести это дело сложно). Но формально это можно разделить на 3 этапа — маркировка, планирование, чистка.

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

И на этапе чистки в зависимости от необходимости компактинга может производится обновление ссылок и компактинг или удаление без перемещений.

#3. Выделение памяти на куче так же быстро, как и на стеке

Опять же, скорее неточность, чем абсолютная неправда. В общем случае, конечно, разница в скорости выделения памяти минимальна. Действительно, в лучшем случае, при bump pointer allocation, выделение памяти — лишь сдвиг указателя, как и на стеке. Однако на выделение памяти в куче могут повлиять такие факторы, как присваивание нового объекта в поле старого (что затронет write barrier, обновляющий card table — механизм, позволяющий отслеживать ссылки из старшего поколения в младшее), наличие финализатора(необходимо добавить тип в соответствующую очередь) и др. Так же, возможно, объект будет записан в одну из свободных дыр в куче (после сборки без дефрагментации). А нахождение такой дыры происходить хоть и быстро, но, очевидно, медленнее, чем простой сдвиг указателя. Ну и разумеется каждый созданный объект приближает очередную сборку мусора. И на очередной процедуре выделения памяти она может случится. Что, естественно, займет некоторое время.

#4. Определение ссылочного, значимого типов и упаковки через понятия стека и кучи

Прямо классика, которая, к счастью, уже не так часто встречается.

Ссылочный тип располагается в куче. Значимый на стеке. Наверняка многие слышали эти определения очень часто. Но мало того, что это лишь частичная правда, так и определять понятия через протекшую абстракцию — не лучшая идея. За всеми определениями предлагаю обращаться к стандарту CLI — ECMA 335. Для начала стоит уточнить, что типы описывают значения. Так, ссылочный тип определяется следующим образом — значение, описываемое ссылочным типом (ссылка) указывает на расположение другого значения. Для значимого типа значение им описываемое является автономным(самосодержащим). Про то, где располагаются те или иные типы ни слова. Это является протекшей абстракцией, которую все же следует знать.

Значимый тип может располагаться:

  1. В динамической памяти (куче), если он является частью объекта, расположенного в куче, или в случае упаковки;
  2. На стеке, если он является локальной переменной/аргументом/возвращаемым значением метода;
  3. В регистрах, если то позволяет размер значимого типа и другие условия.

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

Сама же ссылка может располагаться там же, где и значимый тип.

Упаковка также не определяется через места хранения. Рассмотрим краткий пример.

И соответственный IL код для метода Main

Так как значимый тип является частью ссылочного очевидно, что располагаться он будет в куче. И шестая строка дает ясно понять, что мы имеем дело с упаковкой. Соответственно, типичное определение «копирование из стека в кучу» дает сбой.

Чтобы определить, что есть упаковка, для начала стоит сказать, что для каждого значимого типа CTS(common type system) определяет ссылочный тип, который называется упакованным типом. Так, упаковка — операция над значимым типом, создающая значение соответствующего упакованного типа, содержащего побитовую копию оригинального значения.

#4. События — отдельный механизм

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

К сожалению, зачастую под событием понимается некий отдельный инструмент, тип, механизм. Особенно этому способствует тип из BCL EventHandler, имя которого наталкивает на мысли о том, что это что-то отдельное.

Определение события стоит начать с определения свойств. Я уже давно провел для себя такую аналогию, а недавно увидел, что она проведена и в спецификации CLI.

Свойство определяет именованное значение и методы, которые обращаются к нему. Звучит довольно очевидно. Переходим к событиям. CTS поддерживает события так же, как и свойства, НО методы для доступа отличаются и включают методы для подписки и отписки от события. Из спецификации языка C# — класс определяет событие… что напоминает объявление поля с добавлением ключевого слова event. Тип этого объявления должен быть типом делегата. Спасибо стандарту CLI за определения.

Итак, это означает, что событие — ничто иное, как делегат, который выставляет наружу лишь часть функциональности делегатов — добавление очередного делегата в список для выполнения, удаление из этого списка. Внутри же класса событие ничем не отличается от простого поля типа делегата.

#5. Управляемые и неуправляемые ресурсы. Финализаторы и IDisposable

Абсолютная путаница существует при работе с этими ресурсами. Этому во многом способствует интернет с тысячей статей о правильной реализации паттерна Dispose. Собственно, в этом паттерне ничего криминального нет — модифицированный шаблонный метод под конкретный случай. Но вопрос в другом — нужен ли он вообще. Почему-то, у части людей возникает непреодолимое желание реализовать финализатор на каждый чих. Скорее всего причиной этого является не полное понимание, что есть «неуправляемый ресурс». И строчки про то, что в финализаторах, как правило, освобождаются неуправляемые ресурсы из-за этого неполного понимания проходят мимо и не остаются в голове.

Неуправляемый ресурс — ресурс, который не является управляемым (как бы это странно ни было). А управляемый ресурс, в свою очередь, тот, который выделяется и высвобождается CLI автоматически через процесс который называется сборка мусора. Это определение я нагло содрал из стандарта CLI. Но если попытаться объяснить проще, то неуправляемые ресурсы — те, про которые не знает сборщик мусора. (Строго говоря мы можем давать сборщику немного информации про такие ресурсы с помощью GC.AddMemoryPressure и GC.RemoveMemoryPressure, это может оказать влияние на внутренние самотьюнинги сборщика). Соответственно, он не сможет сам позаботиться об их освобождении и поэтому мы должны сделать это за него. И подходов к этому может быть много. И чтобы код не пестрил от разнообразия воображения разработчиков, используются 2 общепринятых подхода.


  1. Интерфейс IDisposable (и его асинхронная версия IAsyncDisposable). Мониторится всеми анализаторами кода, так что забыть про его вызов сложно. Предоставляет единственный метод — Dispose. И поддержку компилятора — оператор using. Отличный кандидат на тело метода Dispose — вызов аналогичного метода одного из полей класса или освобождение неуправляемого ресурса. Вызывается явно пользователем класса. Наличие данного интерфейса у класса подразумевает, что по окончании работы с экземпляром, нужно вызвать этот метод.
  2. Финализатор. По своей сути является страховкой. Вызывается неявно, в неопределенное время, во время сборки мусора. Замедляет выделение памяти, работу сборщика мусора, продлевает время жизни объектов минимум до следующей сборки, а то и дольше, но зато вызывается сам, даже если его никто не вызывал. Из-за своей недетерминированной природы, в нем должны освобождаться только неуправляемые ресурсы. Также можно встретить примеры, в которых финализатор применялся для воскрешения(resurrection) объекта и организации пула объектов таким образом. Однако такая имплементация пула объектов — однозначно плохая идея. Как и пытаться логировать, кидать исключения, обращаться к базе и тысячи подобных действий.

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

И вопреки утверждению, что Dispose нарушает концепцию, в которой CLR сделает все за нас, заставляет делать что-то самим, о чем-то помнить и тд, скажу следующее. При работе с неуправляемыми ресурсами, надо быть готовым, что они никем, кроме вас, не управляются. И вообще, ситуации, при которых данные ресурсы будут использоваться в ентерпрайсе, почти не встречаются. И в большинстве случаев можно обойтись замечательными классами обертками, вроде SafeHandle, который обеспечивает критическую финализацию ресурсов, предотвращая их преждевременную сборку.

Если же в вашем приложении по тем или иным причинам много ресурсов, требующих дополнительных действий для освобождения, то стоит взглянуть на отличный паттер компании JetBrains — Lifetime. Но не стоит его применять при виде первого же IDisposable объекта.

#6. Стек потока, стек вызовов, вычислительный стек и

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

Стек вызовов — структура данных, а именно стек, для хранения адресов возврата, для возвращения из функций. Стек вызовов — понятие больше логическое. Оно не регламентирует где и как должна храниться информация для возврата. Получается, что стек вызовов — самый обычный и родной нам стек т.е. Stack (Шутка). В нем же хранятся локальные переменные, через него передаются параметры и в нем же сохраняются адреса возврата при вызове инструкции CALL и прерываний, которые впоследствии используются инструкцией RET для возврата из функции/прерывания. Идем дальше. Одним из основных приколов потока является указатель на инструкцию, которая выполняется далее. Поток поочереди выполняет инструкции, объединяющиеся в функции. Соответственно у каждого потока есть стек вызовов. Таким образом получается, что стек потока и есть стек вызовов. То есть стек вызовов данного потока. Вообще, он также упоминается и под другими именами: программный стек, машинный стек.

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

Вычислительный стек (evaluation stack). Как известно, код C# компилируется в IL код, который входит в состав результирующих DLL (в самом общем случае). И как раз в основе среды выполнения, поглощающей наши DLL и выполняющей IL код лежит стек-машина. Почти все IL инструкции оперируют неким стеком. Например, ldloc загружает локальную переменную под определенным индексом на стек. Здесь под стеком понимается некий виртуальный стек, ведь в итоге эта переменная может с высокой вероятностью оказаться и в регистрах. Арифметические, логические и др IL инструкции оперируют с переменными со стека и кладут результат туда же. То бишь вычисления производятся через этот стек. Таким образом получается, что вычислительных стек — абстракция в рантайме. К слову, многие виртуальные машины основаны на стек-машине.

#7. Больше потоков — быстрее код

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

Также пытаться работать с диском из многих потоков — самоубийство. Диск и без того является тормозящим фактором многих программ, которые с ним работают. Если пытаться работать с ним из многих потоков, то надо забыть о быстродействии.

За всеми определениями рекомендую обращаться сюда:

C# Language Specification — ECMA-334
Просто хорошие источники:
Konrad Kokosa — Pro .NET Memory Management
CLI specification — ECMA-335
CoreCLR developers about runtime — Book Of The Runtime
От Станислава Сидристого про финализацию и прочее — .NET Platform Architecture

Отладка кода

В C#, как и в других появившихся до .NET языках, главная методика по отладке состоит в добавлении точек останова и изучении того, что происходит в коде в конкретные моменты во время его выполнения.

Точки останова

Точку останова (breakpoint) в Visual Studio можно помещать на любую строку кода, которая в действительности выполняется. Самый простой способ — щелчок на необходимой строке в окне редактора кода внутри затененной области вдоль левого края окна документа (или выделение нужной строки и нажатие клавиши ). Это приводит к размещению в данной строке точки останова, которая вызывает прерывание процесса выполнения и передачу управления отладчику. Как и в предыдущих версиях Visual Studio, точка останова обозначается большим кружком слева от соответствующей строки в окне редактора кода. Кроме того, Visual Studio выделяет саму строку, отображая ее текст и фон разными цветами. Щелчок на кружке приводит к удалению точки останова.

Если останов на определенной строке каждый раз не подходит для решения имеющейся проблемы, можно создать так называемую условную точку останова. Для этого выберите в меню Debug (Отладка) пункт Windows — Breakpoints (Окнo — Точки останова). Откроется диалоговое окно, позволяющее указать желаемые детали для точки останова. В этом окне можно выполнять следующие действия:

Указать, что выполнение должно прерываться лишь после прохождения точки останова определенное количество раз.

Указать, что точка останова должна вступать в действие при каждом n-ном достижении строки, например, при каждом 20-м ее выполнении (это удобно при отладке больших циклов).

Задать точки останова относительно переменных, а не команд. В таком случае наблюдение будет вестись за значением указанной переменной, и точки останова будут активизироваться при каждом изменении значения этой переменной. Однако этот вариант может сильно замедлить выполнение кода, поскольку на проверку, не изменилось ли значение отслеживаемой переменной после выполнения каждой очередной инструкции, будет тратиться дополнительное время процессора.

Слежения

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

Для просмотра значений переменных можно также использовать окно Autos (Автоматические). Окно Autos представляет собой окно с вкладками, которое появляется лишь тогда, когда программа выполняется в режиме отладки. Если вы его не видите, попробуйте выбрать в меню Debug (Отладка) пункт Windows — Autos (Окна — Автоматические).

В этом окне рядом с переменными, которые являются классами или структурами, отображается пиктограмма с изображением знака «плюс», щелчок на которой позволяет развернуть представление переменной и просмотреть значения ее полей.

Три предлагаемых в этом окне вкладки предназначены для наблюдения за переменными трех разных категорий:

Вкладка Autos (Автоматические) позволяет просматривать значения нескольких последних переменных, к которым осуществлялся доступ в процессе выполнения программы.

Вкладка Locals (Локальные) позволяет просматривать значения переменных, к которым получается доступ в методе, выполняемом в текущий момент

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

Исключения

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

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

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

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

На самом деле в Visual Studio предлагается очень действенное решение. Если заглянуть в меню Debug (Отладка), то можно будет обнаружить там пункт Exceptions (Исключения). В случае выбора этого пункта открывается диалоговое окно Exceptions (Исключения). Это окно позволяет указывать, что должно происходить при выдаче исключения. Здесь можно указать, что выполнение должно продолжаться или же останавливаться с переходом в режим отладки, в случае чего произойдет останов, а отладчик окажется прямо на самом операторе throw:

Visual Studio известно обо всех классах исключений, которые доступны в базовых классах .NET, и о многих таких исключениях, которых могут выдаваться за пределами среды .NET. Распознавать автоматически специальные классы исключений, создаваемые разработчиками, Visual Studio не умеет, но позволяет вручную добавлять такие классы исключений в список и, следовательно, указывать, какие из таких исключений должны приводить к немедленному прекращению выполнения приложения. Для этого необходимо щелкнуть на кнопке Add (Добавить), которая активизируется при выборе самого верхнего узла в дереве, и ввести имя специального класса исключения.

Дополнительные команды отладки исходного кода

Компиляция практически всего коммерческого программного обеспечения на стадии отладки и на стадии подготовки окончательной версии продукта должна проводиться немного по-разному. Среда Visual Studio способна понимать это, поскольку сохраняет информацию обо всех параметрах, которые ей надлежит передавать компилятору. Для поддержки разных вариантов компоновки проекта Visual Studio потребуется сохранять подобную информацию в более чем одном экземпляре. Разные экземпляры такой информации называются конфигурациями. При создании проекта Visual Studio автоматически предлагает на выбор две таких конфигурации, которые называются, соответственно, Debug (Отладка) и Release (Выпуск):

Конфигурация Debug обычно указывает, что никакие операции по оптимизации выполняться не должны, в исполняемом коде должна присутствовать дополнительная отладочная информация, а компилятор должен предполагать, что в коде определен препроцессорный символ отладки Debug, если только он не был явно отменен с помощью директивы #undefined.

Конфигурация Release указывает, что компилятор должен проводить в отношении компилируемого кода оптимизацию, в исполняемом коде не должно присутствовать никакой дополнительной информации, а компилятор не должен предполагать наличие препроцессорного символа Debug.

Можно также определять собственные конфигурации. Это необходимо, например, для компоновки приложения с несколькими отличающимися версиями. Раньше из-за проблем, связанных с поддержкой кодировки Unicode в Windows NT, но не в Windows 95, для многих проектов на С++ было принято создавать две конфигурации — одну для Unicode, а вторую для (multibyte character set — набор многобайтных символов).

Приложение С# не запускается на другом компьютере

Я выполнил свое приложение Windows Forms на Visual Studio 2008 с настройкой «Release». Когда я пытаюсь запустить его на другом компьютере, окна вообще не отображаются. Соответствует Windows 7, на другом компьютере установлен Windows XP. Что это может быть?

Добавлено: Я не создал ни одного установщика. На другой машине есть .net framework 3.0, а не 3.5, но простое приложение hello world работает нормально. Я попытался скопировать программу в другую папку на моем компьютере — никаких изменений.

Двойная проверка версии .NET, если вы создали версию для .NET 3.5, а на другой машине нет .NET 3.5, которая должна быть установлена. Я боюсь, а не только, что не забывайте Пакет обновления 1 также. Взгляните на этот SO поток здесь, чтобы определить установленную версию .NET, запустите его на компьютере, который «кажется сломанным», чтобы посмотреть, какая версия.

Создайте программу установки вместо простого копирования файлов. Это поможет определить, отсутствует ли у вас что-либо, например .net fw 3.5.

10 фич в C#, о которых вы определённо должны узнать и начать их использовать

Если вы только начали изучение C# или же решили расширить свои знания, мы нашли для вас 10 фич, знание которых позволит вам избежать ошибок, писать более понятный код и сохранить кучу времени.

1. async / await

Использование паттернов async / await позволяет разблокировать UI / текущий поток во время выполнения блочных операторов. Паттерны async / await позволяют коду продолжить выполнение, даже если что-то блокирует его выполнение (например, веб-запрос).


2. Инициализаторы объектов / массивов / коллекций

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

3. Лямбды, предикаты, делегаты и замыкания

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

4. ?? (Оператор объединения с NULL)

x ?? y — возвращает x , если значение отличается от null ; в противном случае возвращает y .

Может быть несколько операторов .

?? также может быть использован для перевода типов null в не null :

5. $”” (Интерполяция строк) — C# 6

Фича в C# 6 позволяет эффективно и элегантно собирать строки:

6. ?.(определяет null) — C# 6

x?.y — доступ к членам, определяемый условием null . Возвращает значение null , если левый операнд имеет значение null .

Больше никаких NullReferenceExceptions!

7. Выражение nameof — C# 6

Может показаться, что выражение nameof не особо полезно, но это не так. При использовании автоматических инструментов рефакторинга (например, ReSharper) иногда может потребоваться обратиться к аргументу метода по его имени:

Вот, как это должно быть:

8. Инициализаторы свойств (property) — C# 6

Инициализаторы свойств позволяют задавать начальные значения для свойств:

Польза их использования заключается в том, что вы не можете объявить setter, тем самым делая свойства неизменяемыми. Инициализаторы свойств хорошо работают в связке с синтаксисом первичного конструктора в C# 6.

9. Операторы as и is

Is — совместимость типов. Возвращает значение true, если вычисленный левый операнд может быть приведен к типу, указанному в правом операнде (статический тип).

As — преобразование типов. Возвращает левый операнд, приведенный к типу, заданному правым операндом (статический тип), но as возвращает null , где (T)x вызывает исключение.

10. Ключевое слово yield

Ключевое слово yield позволяет заполнить интерфейс IEnumerable объектами (items). Следующий пример вернет все степени двойки от 2 до 2 в степени 8 (то есть 2, 4, 8, 16, 32, 128, 256):

В правильных руках yield — очень мощная вещь. Оно позволяет с легкостью генерировать последовательность объектов, то есть системе не придется перечислять всю коллекцию целиком — это может быть сделано по требованию.

Перехват клавиатуры Windows на C#

Один из разработчиков обучающей системы с модулем тестирования обратился ко мне с достаточно простой на первый взгляд задачей – как при запуске экзамена не допустить переключения приложения. При всей простоте, задача немного усложнилась тем, что комплекс был разработан на . NET Framework и подключать вставки native кода на C ++ не очень хотелось. На самом деле язык C # на платформе Windows позволяет работать с WIN API . Осталось только привести пример того, как можно осуществить перехват нажатий на клавиши на чуть более низком уровне.

Собственно ниже пример перехвата клавиатуры на языке C#. Пример этот будет работать как на 32х так и на 64 битной Windows . Программа выводит в отладочную консоль нажатия на клавиши в любом приложении, а также производит блокировку нажатия Alt + Tab . Как вы уже понимаете, перехват клавиатуры ведется на уровне всех приложений. При желании можно даже перехватить Ctrl Alt Del но думаю что детали, тем кому это необходимо, выяснят самостоятельно.

internal class HookDemoHelper

private const int WH_KEYBOARD_LL = 13;

private LowLevelKeyboardProcDelegate m_callback;

private IntPtr m_hHook;

[ DllImport ( «user32.dll» , SetLastError = true )]

private static extern IntPtr SetWindowsHookEx(

IntPtr hMod, int dwThreadId);

[ DllImport ( «user32.dll» , SetLastError = true )]

private static extern bool UnhookWindowsHookEx( IntPtr hhk);

[ DllImport ( «Kernel32.dll» , SetLastError = true )]

private static extern IntPtr GetModuleHandle( IntPtr lpModuleName);

[ DllImport ( «user32.dll» , SetLastError = true )]

private static extern IntPtr CallNextHookEx(

int nCode, IntPtr wParam, IntPtr lParam);

private IntPtr LowLevelKeyboardHookProc(

int nCode, IntPtr wParam, IntPtr lParam)

return CallNextHookEx(m_hHook, nCode, wParam, lParam);

var khs = ( KeyboardHookStruct )

Debug .Print( «Hook: Code: <0>, WParam: <1>,<2>,<3>, <4>» ,

nCode, wParam, lParam,

khs.ScanCode, khs.Flags, khs.Time);

if (khs.VirtualKeyCode == 9 &&

khs.ScanCode == 15) //alt+tab

System. Console .WriteLine( «Alt+Tab pressed!» );


IntPtr val= new IntPtr (1);

return CallNextHookEx(m_hHook, nCode, wParam, lParam);

[ StructLayout ( LayoutKind .Sequential)]

private struct KeyboardHookStruct

public readonly int VirtualKeyCode;

public readonly int ScanCode;

public readonly int Flags;

public readonly int Time;

public readonly IntPtr ExtraInfo;

private delegate IntPtr LowLevelKeyboardProcDelegate (

2.2 Создание первого оконного приложения в .NET. «Убегающее окно».

Необходимые знания:

Создавая данную программу, мы рассмотрим основные принципы создания оконных приложений в C#, а также методы реализации с помощью них каких-либо конечных целей: в нашем случае — это забавно убегающее окно.

Создайте новый проект, в качестве типа шаблона установите приложение Windows Forms, как показано на рисунке 1:
Рисунок 1. Создание нового проекта.
Назовите проект RandWindow и нажмите кнопку ОК.

Рабочее окно MS Visual Studio содержит следующие вспомогательные окна (рис. 2).
Рисунок 2. Вспомогательные окна.
На рисунке цифрам отмечены:

  1. Окно Toolbox (Панель элементов управления) — элементы управления вы можете разместить на создаваемой форме.
  2. Окно Solution Explorer (Обозреватель решений) — здесь вы сможете увидеть следующие узлы: Properties — настройки проекта, Links (Ссылки) — подключенные к проекту библиотеки, а также созданные и подключенные к проекту файлы исходных кодов (с расширением .cs) и подключенные к проекту формы (например, Form1).
  3. Окно Class View (Окно классов) — здесь представлены все созданные в программе классы.
  4. Окно Properties (Свойства) — выбрав любой элемент управления или даже форму, вы сможете увидеть все параметры данного объекта, а также изменить значения, установленные в них по умолчанию.

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

Добавление новых элементов управления на форму

Итак, после того как вы ввели имя проекта, установили необходимый шаблон и нажали кнопку ОК, MS Visual Studio автоматически создаст каркас оконного приложения, после чего мы сможем добавить на него новые оконные элементы.

Для этого необходимо перетащить необходимый оконный элемент из окна инструментов (ToolBox).

Нашему окну потребуется 2 элемента поля для ввода, в которые мы будем выводить координаты указателя мыши, что облегчит нам понимание работы программы.

В центре окна будет находиться надпись, которую мы создадим с помощью элемента Label.
Снизу будут расположены 2 кнопки.

Немного растяните заготовку окна. Если вы нажмете на него правой кнопкой, то откроется контекстное меню. В нем нажмите на пункте свойства, после чего вы сможете изучить различные параметры окна, которые вы можете изменить. На рисунке 3 изображены самые (как правило) необходимые свойства:
Рисунок 3. Различные свойства окна (формы) в C# .NET.
Немного растяните заготовку окна и добавьте все необходимые элементы. На рисунке 4 вы можете увидеть их в окне ToolBox:
Рисунок 4. Перетаскивайте необходимые элементы из окна Toolbox на создаваемую форму.

Перейдите в свойства строки Label1, где измените текст на «Вы стремитесь сделать мир лучше?». Также измените тип шрифта, для этого найдите свойство Font (рис. 5).
Рисунок 5. Свойство Font элемента Label.
После чего установите тип шрифта Tahoma, ширину шрифта Bold и размер равный 16 (рис. 6).
Рисунок 6. Установки шрифта.
Далее измените текст на кнопках, используя свойство Text.

Полученная заготовка окна программы будет выглядеть следующим образом (рис. 7).
Рисунок 7. Форма будет выглядеть следующим образом.

Техническая часть работы программы

  1. Сначала мы добавим обработчик события перемещения мыши и реализуем вывод ее координат x и y в два созданных поля ввода.
  2. Далее мы создадим функции обработчики щелчка по каждой из клавиш мыши (особенно усердные пользователи все же смогут попасть по кнопке «Да, конечно!»).
  3. Далее мы добавим код, реализующий случайное перемещение окна в том случае, если курсор приблизиться к кнопке «Да, конечно!».

Определение перемещения указателя мыши по форме

Щелкните непосредственно на части формы создаваемого приложения (НЕ на одном из элементов).

Теперь перейдите к свойствам формы с помощью щелчка правой кнопки мыши -> контекстное меню свойства.

Теперь необходимо перейти к списку возможных событий, которые может получать данное окно. Для этого щелкните на кнопке «Event» (события), как показано на рисунке 8:
Рисунок 8. Переход к списку возможных событий.
Когда пользователь передвигает указатель мыши по нашему окну, операционная система посылает сообщение программе с текущими координатами указателя. Они-то нам и нужны.

Чтобы назначить обработчик данного события, найдите строку MouseMove (рис. 9), после чего сделайте двойной щелчок в поле справа от нее – автоматически добавится обработчик события движения мыши и добавится функция Form1_MouseMove в коде нашей программы.
Рисунок 9. После двойного щелчка справа от MouseMove появиться данная строка, и автоматически совершится переход к коду функции-обработчика данного события.
Добавьте в эту функцию 2 строки, чтобы ее код стал выглядеть следующим образом.

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

textBox1 и textBox2 это экземпляры класса textbox, реализующие управление нашими элементами поля для ввода.

Член данных экземпляров Text позволяет установить текст в данных полях.

Таким образом, если теперь откомпилировать программу (F5), при перемещении указателя мыши по форме окна мы будем видеть координаты указателя (внутри формы), которые будут непрерывно изменяться.

Теперь вернемся к заготовке нашей формы. Для это щелкните на соответствующей закладке (Form1.cs [Конструктор]), как показано на рисунке 10:
Рисунок 10. Переход к конструктору форм C#.
Сделайте двойной щелчок по первой кнопке: Visual Studio автоматически добавит код обработки данной кнопки при нажатии.

Добавьте следующие строки кода:

Теперь снова вернитесь к конструктору и добавьте вторую кнопку, также с помощью двойного щелчка по ней.

Она будет содержать следующий код:

Как видите, здесь мы немного усложнили код вызова окна-сообщения, чтобы продемонстрировать то, как оно работает, более подробно. Все параметры передаваемые в функцию Show закомментированны в исходном коде.

Теперь нам осталось только реализовать перемещение окна в тот момент, когда мышь приближается к кнопке «Да, конечно».

Для этого мы добавим код в функцию:

private void Form1_MouseMove(object sender, MouseEventArgs)

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

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

Также нам понадобится объявить несколько «рабочих» переменных, которые мы будем в дальнейшем использовать.

Генерация случайных чисел

Класс Random в C# представляет собой генератор псевдослучайных чисел — т.е. данный класс отвечает за выдачу последовательности чисел, отвечающую определенным статистическим критериям случайности.

Random rnd = new Random();

Здесь мы объявили экземпляр класса Random (rnd), с помощью которого мы будем генерировать случайные числа. В дальнейшем мы будем использовать код, вида rnd.Next (диапазон_генерации) или rnd.Next (от, до -1) для генерации случайного числа.

Также мы объявим еще несколько переменных, часть из которых сразу будет инициализирована.

tmp_location объявляется для того, чтобы в будущем временно хранить текущее положение окна.

Также нам следует подумать о том, что при случайном перемещении, наше окно может выйти далеко за пределы экрана.

Чтобы определить разрешение экрана в C# .NET, мы будем использовать:

_h и _w будут хранить в себе размеры экрана пользователя, которые определяются при их инициализации.

Теперь код этой функции будет выглядеть следующим образом:

Вот, собственно, и все. Откомпеллировав приложение, можете попробовать нажать на кнопку «Да, конечно». Это будет крайне трудно.

Цукерберг рекомендует:  Обзорный вебинар по курсу Язык С
Понравилась статья? Поделиться с друзьями:
Все языки программирования для начинающих