Результати пошуку за запитом: видеокурс c*
Використання календаря в Microsoft Outlook
Автор: Олександр Марченко
Введение
В современной компании Вам придется работать в команде, а это означает, что впредь Вы обязаны планировать совместные активности, уведомлять своих коллег о вашем отсутствии на рабочем месте и доступности к рабочим встречам.
В решении Microsoft Outlook присутствует множество возможностей для упрощения и автоматизации данного процесса. Так, одним из самых часто востребованных является планировщик задач и событий. Раздел «Календарь» позволяет пользователю совмещать на одном экране несколько календарей, принадлежащих как разным учетным записям, так и разным сотрудникам, автоматически отбирать все встречи одного сотрудника по определенному проекту или департаменту, просматривать календари коллег и планировать совместные мероприятия.
Так выглядит незапланированная неделя в вашем календаре. К тому же вы можете настроить ее отображение под себя. Для этого достаточно перейти в меню File//Options//Calendar
А вот так может выглядеть неделя, на которой назначено несколько рабочих задач, пара встреч, уведомление о недоступности на весь день и внесена личная встреча.
Так, зеленым цветом помечены события из рабочей категории, их отличительная особенность – возможность смещаться по времени, бордовым отмечены корпоративные собрания, которые не могут смещаться по времени, красным отмечено событие, которое попадает в категорию «Личное» и не подлежит разглашению. Кроме того, 16 июля мы видим событие, которое будет распространятся на весь день, а его подпись гласит, что мы будем недоступны для наших коллег.
В следующей статье мы детально рассмотрим процесс создания и редактирования событий и задач в разделе «Календарь» из Microsft Outlook 2013.
Заміщення методу С#
Автор: Редакция ITVDN
Введение
В данной статье Вы узнаете, для чего и как использовать замещение метода в C#.
Для того, чтобы на примере показать замещение метода в С#, создадим класс «Student» с двумя полями: FirstName и LastNamе. В примере используется также метод печати, который выводит FirstName и LastName в консоль.
class Student {
public string FirstName;
public string LastName;
public virtual void Print() {
Console.WriteLine(FirstName + " " + LastName);
}
}
Класс Student выступает как базовый/родительский класс для классов DiplomaStudent и GraduateStudent.
class DiplomaStudent : Student {
}
class GraduateStudent : Student {
}
ПРИМЕЧАНИЕ: Если производный класс наследует базовый класс, то все учасники, кроме частных членов, доступны в производном классе. То есть, оба поля и метод печати можно вызвать/инициировать в производном классе.
Если нужно распечатать детали студентов на экране консоли, можно создать пример двух производных классов от «Student», используя основной метод.
class Program {
static void Main(string[] args) {
DiplomaStudent ds = new DiplomaStudent();
ds.FirstName = "Max";
ds.LastName = "Payne";
ds.Print();
GraduateStudent gs = new GraduateStudent();
gs.FirstName = "Lara";
gs.LastName = "Croft";
gs.Print();
}
}
Запустите программу.
На данном этапе невозможно определить, к какому типу из категорий студентов принадлежит каждый студент. Например, добавим (-studentType) и прикрепим его после имени студента, чтобы сделать его более удобным для чтения.
Для этого можно создать метод печати для обоих производных классов.
class DiplomaStudent : Student {
public void Print() {
Console.WriteLine(FirstName + " " + LastName + " - diploma student");
}
}
class GraduateStudent : Student {
public void Print() {
Console.WriteLine(FirstName + " " + LastName + " - graduate student");
}
}
Но если Вы хотите не скрыть реализацию базового метода, а заместить ее, то можно использовать виртуальное ключевое слово.
class Student {
public string FirstName;
public string LastName;
public virtual void Print() {
Console.WriteLine(FirstName + " " + LastName);
}
}
Теперь базовый метод печати стал виртуальным. То есть, его можно заменить в производном классе и добавить его реализацию.
Но сначала надо удалить метод печати с обоих производных классов, как показано ниже:
class DiplomaStudent : Student {
}
class GraduateStudent : Student {
}
Напишите override, потом поставьте пробел. Вы увидите метод печати в Intellisense.
Выберите и нажмите Enter. Он унаследует метод сигнатур.
class DiplomaStudent : Student {
public override void Print() {
base.Print();
}
}
class GraduateStudent : Student {
public override void Print() {
base.Print();
}
}
Удалите его и добавьте свою собственную реализацию, как показано ниже:
class DiplomaStudent : Student {
public override void Print() {
Console.WriteLine(FirstName + " " + LastName + " - diploma student");
}
}
class GraduateStudent : Student {
public override void Print() {
Console.WriteLine(FirstName + " " + LastName + " -graduate student");
}
}
Запустите программу.
Предположим, что по какой-то причине Вам необходимо отменить реализацию вызова и печати базового класса. Это можно сделать при помощи такой комбинации: основное ключевое слово, затем точка (.), потом метод.
class DiplomaStudent : Student {
public override void Print() {
base.Print();
}
}
Источник: http://www.c-sharpcorner.com/UploadFile/219d4d/method-overriding-in-C-Sharp/
Створення Super Meat Boy на Unity
Автор: Антон Даніелян
Введение
Данная статья ориентирована на тех, у кого уже есть небольшой опыт работы с Unity. В первую очередь мы рассмотрим воссоздание механики управления главного героя игры Super Meat Boy. Также узнаем, как построить сцену, имея скриншот уровня оригинальной игры. Все материалы, использованные в данном примере, принадлежат разработчикам оригинальной игры.
Для начала стоит сказать пару слов о фоновых картинках для уровней. Чтоб не создавать весь уровень из отдельных элементов, редактируем найденные на просторах интернета скриншоты, на которых вырезаем главного героя, таймер с левой части экрана и следы крови. Теперь у нас есть подготовленный фон.
Элементы Уровня
Поверхности, по которым можно двигаться, задаем с помощью компонента Polygon Collider 2D. Места, где игрок может умереть (выпасть из поля зрения камеры или попасть на режущую пилу) обозначаем тегом killzone. К ним крепим данный скрипт:
void OnTriggerEnter2D(Collider2D other)
{
if (coll.tag =="killzone")
{
Application.LoadLevel(Application.loadedLevelName);
}
}
При прикосновении коллайдер игрока вызывает срабатывание скрипта и подгружает этот же уровень, то есть происходит рестарт. Аналогично работает и загрузка следующего уровня, единственным отличием является передаваемое методу Application.LoadLevel() текстовое значение с названием уровня. Этот скрипт прикрепляем к объекту endTarget.
Следы крови размещаем на все потенциально доступные игроку поверхности (кроме уровня песочницы, где они находятся на каждой из 4 сторон блока). Они состоят из отключенного по умолчанию компонента Sprite Renderer, компонента Box Collider 2D с активированным значением IsTrigger и скрипта, который собственно и включает Sprite Renderer при коллизии с игроком.
SpriteRenderer sR;
void Start()
{
sR = transform.GetComponent<SpriteRenderer>();
}
void OnTriggerEnter2D(Collider2D coll)
{
if (coll.tag =="Player")
{
sR.enabled = true;
}
}
Получаем компонент Sprite Renderer во время выполнения при помощи метода GetComponent(), вызываемого на данном объекте. Если тег прикасающегося коллайдера равен "Player", то включаем Sprite Renderer, который отображает картинку крови на уровне.
Создание персонажа
Внешний вид персонажа
В оригинальной игре мит-бой тщательно анимирован и имеет большое количество визуальных эффектов, большинство из которых мы воссоздавать не будем по причине нецелесообразности. Вместо анимации будем использовать простую подмену спрайтов при смене состояния игрока. Для главного персонажа нам понадобятся компоненты Rigid Body 2D, Sprite Renderer, Box Collier 2D, Circle Collider 2D и скрипт управления, который мы рассмотрим чуть ниже.
В инспекторе на компоненте Rigid Body 2D ставим галочку на Fixed Angle, в Circle Collider 2D на IsTrigger. Этим мы зафиксировали персонажа в одном положении и указали, что Circle Collider 2D выполняет функцию триггера. Радиус окружности коллайдера должен быть таким, что немного выходит за рамки квадратного коллайдера. Он является триггером появления следов крови на уровне.
Объявление переменных
Для корректной имитации поведения нам понадобятся переменные для скорости ходьбы, бега, прыжка, а также ускорения в воздухе и на земле.
public float jumpForce = 50f;
public float speed = 10;
public float speedMultiplier = 4f;
public float acceleration = 5f;
public float airAcceleration = 2f;
Для данных переменных экспериментальным путем были подобраны значения, которые больше всего напоминают поведение оригинала.
Также нам понадобятся переменные для контроля вида персонажа и собственно его физика. Они позже будут инициализированы уже знакомым нам способом во время выполнения.
SpriteRenderer spriteRender;
Rigidbody2D rBody;
Для правильного отображения разных состояний мит-боя будем использовать несколько картинок, поэтому берем переменные типа Sprite.
//спрайты разных состояний
public Sprite jumpSprite;
public Sprite RunSprite;
public Sprite IdleSprite;
public Sprite SlidingOnAWallSprite;
Данные спрайты будем инициализировать не в рантайме, а в редакторе, где проводим им ссылку на картинку для каждого состояния.
И напоследок еще понадобятся данные о высоте, толщине персонажа и состояние прыжка.
float playerWidth;
float playerHeight;
//флаг состояния прыжка
bool ableToJump = true;
Управление главным героем
После объявления всех нужных нам переменных, переходим к реализации. Зарезервированный метод Awake() отработает сразу поле загрузки уровня, поэтому в нем и инициализируем переменные толщины, высоты и другие.
void Awake()
{
//инициализация этих переменных произойдет сразу после запуска сцены
playerWidth = GetComponent<BoxCollider2D>().bounds.extents.x + 0.05f;
playerHeight = GetComponent<BoxCollider2D>().bounds.extents.y + 0.05f;
rBody = transform.GetComponent<Rigidbody2D>();
spriteRender = transform.GetComponent<SpriteRenderer>();
}
Переменные playerHeigth и palyerWidth будут полезны при определении, находится ли игрок на земле. К ним прибавляем небольшой зазор, который не даст лучу от персонажа заметить его же коллайдер.
Метод IsOnGround() возвращает true в случае, если хотя бы один из созданных лучей касается коллайдера. Для удобства создаем два луча – с левой нижней части коллайдера персонажа и правой соответственно. При создании отнимаем высоту, учитывая вертикальный и горизонтальный зазоры. Этот способ позволит уйти от многих проблем при прыжках возле стен.
public bool IsOnGround()
{
//создаем луч длинной 0.01 справа с направлением вниз
bool rightBottom = Physics2D.Raycast(
new Vector2(transform.position.x + playerWidth - 0.055f,
transform.position.y -playerHeight), -Vector2.up, 0.01f);
//аналогичный луч слева
bool leftBottom = Physics2D.Raycast(
new Vector2(transform.position.x - playerWidth + 0.055f,
transform.position.y - playerHeight),-Vector2.up, 0.01f);
return (rightBottom || leftBottom) ? true : false;
}
Метод Run() отвечает за движение игрока по горизонтали. Параметр int directionX отвечает за направление, если число позитивное, то двигаемся вправо, негативное – влево соответственно. Если нажат LShift, то учитывается умножитель ускорения. Если игрок находится в воздухе, то множим на переменную ускорения в воздухе.
private void Run(bool onGround, int directionX)
{
rBody.AddForce(new Vector2((directionX * speed - rBody.velocity.x) *
(Input.GetKey(KeyCode.LeftShift) ? speedMultiplier : 1f) *
(onGround ? acceleration : airAcceleration), 0));
}
Метод JumpNearWall() отвечает за прыжок персонажа возле стены. Аналогично методу Run(), он принимает параметр int directionX.
private void JumpNearWall(int directionX)
{
//убираем инерцию
rBody.velocity = Vector2.zero;
rBody.AddForce(new Vector2(directionX *
jumpForce * airAcceleration * 3,
jumpForce * airAcceleration * 5));
StartCoroutine(JumpCoolDown());
}
В конце тела этого метода вызываем корутин, который будет убирать возможность прыгать суммарно на 0.1 секунд.
IEnumerator JumpCoolDown()
{
yield return new WaitForSeconds(0.05f);
ableToJump = false;
yield return new WaitForSeconds(0.05f);
ableToJump = true;
}
Метод FlipPlayer() меняет направление используемого спрайта игрока.
void FlipPlayer(bool toLeft)
{
//если повернут направо, а нужно налево
if ((transform.localScale.x < 0 && toLeft) ||
//если повернут налево, а нужно направо
(transform.localScale.x > 0 && !toLeft))
{
transform.localScale = new Vector3(transform.localScale.x * -1f,
transform.localScale.y, transform.localScale.z);
}
}
Метод FixedUpdate() является зарезервированным и вызывается независимо от количества отработанных кадров. Для начала получаем значение, касается ли персонаж пола и стен слева и справа.
bool onGround = IsOnGround();
bool nearLwall = Physics2D.Raycast(
new Vector2(transform.position.x - playerWidth, transform.position.y),
-Vector2.right, 0.01f);
bool nearRwall = Physics2D.Raycast(
new Vector2(transform.position.x + playerWidth, transform.position.y),
Vector2.right, 0.01f);
Присваиваем спрайт по умолчанию – спрайт безделья.
spriteRender.sprite = IdleSprite;
Теперь считываем нажатие кнопок управления.
if (Input.GetKey(KeyCode.RightArrow))
{
//двигаем персонажа в позитивном направлении по оси Х
if (!nearRwall) Run(onGround, 1);
//присваиваем новый спрайт и меняем его направление
spriteRender.sprite = RunSprite;
FlipPlayer(false);
}
else if (Input.GetKey(KeyCode.LeftArrow))
{
//двигаем персонажа в негативном направлении по оси Х
if (!nearLwall) Run(onGround, -1);
spriteRender.sprite = RunSprite;
FlipPlayer(true);
}
Если персонаж находится на поверхности и нажат пробел, то выполняем прыжок и активируем таймер до следующего прыжка.
if (Input.GetKeyDown(KeyCode.Space) && onGround && ableToJump)
{
//выполняем "прыжок с земли"
rBody.AddForce(new Vector2(0, jumpForce * acceleration* 1.7f));
spriteRender.sprite = jumpSprite;
//таймер до следующего прыжка
StartCoroutine(JumpCoolDown());
}
В противном случае разделяем поведение для прыжка возле левой и правой стенки.
if (Input.GetKeyDown(KeyCode.Space) && nearLwall && ableToJump)
{
//прыжок от стены вправо
JumpNearWall(1);
}
if (Input.GetKeyDown(KeyCode.Space) && nearRwall && ableToJump)
{
//прыжок от стены влево
JumpNearWall(-1);
}
Если игрок возле стенки, меняем спрайт и уменьшим скорость вертикального движения при прикосновении к стене после прыжка. Поворачиваем спрайт в нужном направлении и скрипт управления готов.
spriteRender.sprite = SlidingOnAWallSprite;
rBody.velocity = new Vector2(rBody.velocity.x,
(rBody.velocity.y > 9.0f) ? rBody.velocity.y * 0.6f : rBody.velocity.y);
if (nearLwall) FlipPlayer(true);
else FlipPlayer(false);
Теперь осталось опробовать все на практике. К данной статье прикреплен проект с уровнем «песочница», который можно изменить, как угодно добавив или убрав элементы.
Процедури та таймінг у відділі SEO
Автор: Андрій Афанасьєв
Введение
Всем привет! У меня давно созрела навязчивая мысль написать о том, какой является структура работы в техническом отделе SEO. “Почему именно такая тематика?” - спросите Вы. Это наболевшее. Иногда клиенты, да и просто люди, которые не занимаются всерьез данным продуктом, смотрят на весь процесс со стороны и думают: “Да это же просто дело. Взял проектик, денек-два оптимизировал сайт, ссылочек подкупил, всего делов. Может мне и самому SEO заняться?” Забавляет и интернет-пространство, например, рекламой с лозунгами наподобие: “Хватит платить сеошникам. Продвинь свой сайт самостоятельно!”. Это не может не веселить, если, конечно, не учитывать, что часть пользователей все-таки ведутся на подобные вещи.
Ну а если всерьез, то я скажу банальную вещь, что любая стоящая работа требует не менее качественного подхода. Любое интернет-агентство маленького, среднего или большого размаха разрабатывает и выстраивает свой процесс отработки клиентских проектов. В данной статье мы рассмотрим только работу технического отдела, потому что существует еще и аккаунтинг, и топ-менеджмент, которые тоже важны во взаимодействии компании и клиента. Но там “своя кухня” и она несколько отличается от технической.
Идем дальше…
Как известно, для того, чтобы построить качественный и надежный дом, нужно начать с фундамента. Так вот, в отделе SEO таковым является регламент процедур и тайминга. Это путеводитель как для руководителя отдела, так и для остальных членов команды. Зачем он нужен?
Отвечаю. У каждой компании в отработке находится много текущих + еженедельный поток новых клиентов, которые требуют в разы больше внимания, чем текущие. Когда я приведу пример технологии Abweb, Вы поймете критическую важность этого регламента. Если одновременно ведется работа по десяткам проектов, просто физически невозможно держать все в голове. Необходимо иметь универсальный план действий, который разбит на множество подзадач и переносить его в проекцию каждого проекта.
Ну, теперь конкретно о процессах
Для того, чтобы всю информацию было проще воспринять, я четко структурирую все процессы в виде двух таблиц. Как правило, процесс продвижения можно условно поделить на 2 глобальных этапа: внутренняя и внешняя оптимизация. Поэтому и процедуры для них разные.
Внутренняя оптимизация (1-й месяц)
Процедура
Старт выполнения
Тайминг
Проверка доступов от клиента (админка, FTP, хостинг)
1-й день работ
5 рабочих дней
Создание папки проекта и файла проекта в CRM с семантикой и основными доступами
1-й день работ
Анализ проекта, составление технического задания по внутренней оптимизации для программиста и техническое задание для копирайтера
2-й день работ
Отправка сформированных технических заданий аккаунт-менеджеру, который ведет проект.
В тот же день, когда составлено ТЗ, но не позднее 5-ого рабочего дня со старта проекта
Внедрение правок на тестовом домене.
В день, когда аккаунт-менеджер дал сигнал, что ТЗ на оптимизацию утверждено клиентом.
5 рабочих дней (4 дня реализация + 1 день на исправление багов по программной части)
Написание текстов для целевых страниц.
В день, когда аккаунт-менеджер дал сигнал, что ТЗ на тексты утверждено клиентом.
Отправка выполненного ТЗ по оптимизации на тестовом домене аккаунт-менеджеру.
В день, когда ТЗ было полностью внедрено и проверено.
1 рабочий день
Отправка написанных текстов аккаунт-менеджеру.
В день, когда тексты были полностью написаны и проверены.
Перенос выполненных правок на основной домен.
В день, когда аккаунт-менеджер дал сигнал, что ТЗ на тестовом утверждено клиентом.
2 рабочих дня
Размещение текстов.
В день, когда аккаунт-менеджер дал сигнал, что клиент утвердил тексты.
3 рабочих дня
Тестирование основной функциональности сайта после внесенных правок (форм заказа, авторизация, регистрация, добавление контента и его сохранение и т.д.) + исправление багов, если они есть
В день, когда все правки по внутренней оптимизации были перенесены на основной домен.
2 рабочих дня
Отправка сайта и целевых страниц на принудительную переиндексацию поисковыми системами для скорейшего индексирования ПС
В день, когда все правки по внутренней оптимизации были перенесены на основной домен + протестирован основной функционал
1 рабочий день
Добавление сайта в систему мониторинга для отслеживания позиций.
Когда все внедрено, отправлено на переиндексацию.
Итого примерно
19 рабочих дней
Ситуация выглядит таким образом, что за 16 рабочих дней (условно 3 рабочих недели) вся оптимизация должна быть внесена на основной версии сайта. 1 рабочая неделя отводится на тестирование выполненных правок, переиндексацию сайта, мониторинг динамики по позициям и составления отчета по всей проделанной работе.
Обращаю внимание, что тут предлагается такой подход, в котором сначала все внедряется на тестовой копии (которую обязательно нужно закрыть от индексации), демонстрируется и согласовывается с клиентом и, если все OK, переносится на основной домен. Я склонен считать, что это процесс затратный по времени, но зато безопасный!
Переходим ко второму и последующим месяцам.
Второй и дальнейшие месяцы плюс-минус похожи в плане выполняемых процессов.
Внешняя оптимизация (2-й и последующие месяцы)
Процедура
Старт выполнения
Тайминг
Планирование и составление ссылочной стратегии в виде ТЗ со списком закупаемых анкоров.
После получения оплаты
3 рабочих дня
Регистрация аккаунтов для закупки ссылок по проекту
1 этап закупки ссылок
На 4-й рабочий день
2 рабочих дня
Пополнение ссылочного аккаунта для 1 этапа
Плановая проверка сайта на предмет внутренней оптимизации/составление ТЗ по дооптимизации/отправка аккаунт-менеджеру на утверждение
12-й рабочий день
2 рабочих дня
Внедрение правок по дооптимизации на основании предыдущего пункта
В день, когда аккаунт-менеджер дал сигнал, что ТЗ на дооптимизацию утверждено клиентом.
4 рабочих дня
Пополнение ссылочного аккаунта для 2 этапа
14-й рабочий день
2 рабочих дня
2 этап закупки ссылок
Модерация ссылочных бирж
1 раз в 2 рабочих дня
11 рабочих дней
Наполнение ТЗ на ссылки списком доноров, откуда куплены ссылки
За день до составления и отправления отчета аккаунт-менеджером.
1 рабочий день
Итого примерно
22 рабочих дня
Выше приведена таблица со всеми процедурами и ориентировочными дедлайнами по каждому из них.
Хочу сделать акцент на том, что весь этот грандиозный план действий должен быть ориентиром, но всегда бывают исключения. Сроки реализации задач часто зависят от сложности и объема работ по проекту, оперативности клиента по согласованиям технических заданий, текстов и внесенных правок. Могут также вклиниваться и форс-мажорные задачи, которых мы, как правило, не ожидаем. К таким нюансам нужно быть морально готовым и все равно максимально выстроить процессы под нужные дедлайны.
Достаточно ли этого?
Буду честен. Конечно, нет. Недостаточно лишь прописать процедуры. Чтобы все было “в ажуре”, Вам и нам нужны:
Квалифицированные и перспективные ребята, которые будут закрывать все вопросы и задачи, которые расписаны выше (SEO-специалисты, копирайтеры, программисты и т.д.);
Календарные планы по процессам. Например, календарный план по закупке ссылочной массы на каждый месяц, который позволит не запутаться в большом потоке, когда что закупать;
Правильная постановка задач друг другу в худшем случае с помощью блокнота, а в лучшем - CRM-систем или других программ для фиксирования задач и планирования;
Высокая степень самоорганизованности и четко выстроенный тайм-менеджмент у каждого сотрудника;
Регулярное проведение планерок.
Я с удовольствием поделился с Вами прототипом своего видения по выстраиванию процессов в отделе производства SEO. Буду рад услышать замечания и положительные отзывы. На сегодня пока все;)
Реалізація успадкування перерахувань за допомогою розширення для Visual Studio, що базується на Roslyn
Автор: Редакция ITVDN
Введение
В С# программировании необходима возможность расширять простое уравнение. Например, когда нужно использовать перечисления из библиотеки dll, которые невозможно изменить в коде, но и в то же время нужно использовать дополнительные значения, которых нет в библиотеке. Решить проблему можно при помощи системы Roslyn, основанной на расширении VS для создания отдельных файлов. Данный подход похож на моделирование множественного наследования в шаблоне "Implementing Adapter Pattern" и "Imitating Multiple Inheritance" в C# с использованием системы Roslyn, основанной на VS Extension Wrapper Generator.
Формулировка проблематики
Обратите внимание на схему EnumDerivationSample. Она содержит негенерированный код, большая часть которого будет сгенерирована позже. Схема содержит тип перечисления BaseEnum:
public enum BaseEnum
{
A,
B
}
Также в ней присутствует тип перечисления DerivedEnum
public enum DerivedEnum
{
A,
B,
C,
D,
E
}
В перечислении DerivedEnum перечень значений А и В такие же, как в перечислении BaseEnum.
Файл DerivedEnum.cs также содержит статический класс DeriveEnumExtensions для конвертации BaseEnum в DerivedEnum и наоборот:
public static class DeriveEnumExtensions
{
public static BaseEnum ToBaseEnum(this DerivedEnum derivedEnum)
{
int intDerivedVal = (int)derivedEnum;
string derivedEnumTypeName = typeof(DerivedEnum).Name;
string baseEnumTypeName = typeof(BaseEnum).Name;
if (intDerivedVal > 1)
{
throw new Exception
(
"Cannot convert " + derivedEnumTypeName + "." +
derivedEnum + " value to " + baseEnumTypeName +
" type, since its integer value " +
intDerivedVal + " is greater than the max value 1 of " +
baseEnumTypeName + " enumeration."
);
}
BaseEnum baseEnum = (BaseEnum)intDerivedVal;
return baseEnum;
}
public static DerivedEnum ToDerivedEnum(this BaseEnum baseEnum)
{
int intBaseVal = (int)baseEnum;
DerivedEnum derivedEnum = (DerivedEnum)intBaseVal;
return derivedEnum;
}
}
Преобразование значений BaseEnum в DerivedEnum всегда проходит успешно, в то время как преобразование в обратном направлении может быть проблематичным. Например, если значение DerivedEnum больше 1 (значение BaseEnum.B – наибольшее значение в типе перечисления BaseEnum). Функция Program .Main (...) используется для тестирования функциональных характеристик:
static void Main(string[] args)
{
DerivedEnum derivedEnumConvertedValue = BaseEnum.A.ToDerivedEnum();
Console.WriteLine("Derived converted value is " + derivedEnumConvertedValue);
BaseEnum baseEnumConvertedValue = DerivedEnum.B.ToBaseEnum();
Console.WriteLine("Derived converted value is " + baseEnumConvertedValue);
DerivedEnum.C.ToBaseEnum();
}
Будет выводиться:
Derived converted value is A
Base converted value is B
И тогда появится такое сообщение:
"Cannot convert DerivedEnum.C value to BaseEnum type, since its integer value 2 is greater than the max value 1 of BaseEnum enumeration."
Использование Visual Studio Extension для формирования наследования перечислений.
Установите расширение NP.DeriveEnum.vsix Visual Studio из папки VSIX, дважды кликнув на файл. Откройте схему EnumDerivationWithCodeGenerationTest. Тип ее перечислений такой же, как и в предыдущей схеме:
public enum BaseEnum
{
A,
B
}
Посмотрите на файл "DerivedEnum.cs":
[DeriveEnum(typeof(BaseEnum), "DerivedEnum")]
enum _DerivedEnum
{
C,
D,
E
}
Он определяет такой тип перечисления _DerivedEnum с атрибутом: [DeriveEnum (TypeOf (BaseEnum), "DerivedEnum")]. Атрибут определяет "супер-перечисления" (BaseEnum) и названия производного перечисления ("DerivedEnum»). Обратите внимание, что поскольку частичные перечисления не поддерживаются в C#, нам придется создать новый тип перечисления, объединив значение от "супер" до "суб" перечислений.
Посмотрите характеристики файла DerivedEnum.cs, его "специальные инструменты (Custom Tool)" уже содержатся в "DeriveEnumGenerator":
Теперь откройте файл DerivedEnum.cs в Visual Studio, попробуйте изменить его (скажем, добавив пробел) и сохраните его. Вы увидите, что сразу будет создан файл DerivedEnum.extension.cs:
Этот файл содержит тип перечисления DerivedEnum, который объединяет все поля перечислений BaseEnum и _DerivedEnum. Для начала убедитесь, что они имеют одинаковое имя и полное значение, а также имеют соответствующие поля в исходных перечислениях:
public enum DerivedEnum
{
A,
B,
C,
D,
E,
}
Расширение VS также формирует статический класс DerivedEnumExtensions, содержащий методы преобразования между суб и супер перечислениями:
static public class DerivedEnumExtensions
{
public static BaseEnum ToBaseEnum(this DerivedEnum fromEnum)
{
int val = ((int)(fromEnum));
string exceptionMessage = "Cannot convert DerivedEnum.{0} value to BaseEnum - there is no matching value";
if ((val > 1))
{
throw new System.Exception(string.Format(exceptionMessage, fromEnum));
}
BaseEnum result = ((BaseEnum)(val));
return result;
}
public static DerivedEnum ToDerivedEnum(this BaseEnum fromEnum)
{
int val = ((int)(fromEnum));
DerivedEnum result = ((DerivedEnum)(val));
return result;
}
}
Если использовать метод Program.Main (...), как и в предыдущем образце, получим достаточно похожий результат:
static void Main(string[] args)
{
DerivedEnum derivedEnumConvertedValue = BaseEnum.A.ToDerivedEnum();
Console.WriteLine("Derived converted value is " + derivedEnumConvertedValue);
BaseEnum baseEnumConvertedValue = DerivedEnum.B.ToBaseEnum();
Console.WriteLine("Base converted value is " + baseEnumConvertedValue);
DerivedEnum.C.ToBaseEnum();
}
Вы можете указать значение поля как в суб, так и в супер перечислениях. Генератор кода достаточно развит для того, чтобы выдавать правильный код. Например, если мы поставим значение BaseEnum.B 20:
public enum BaseEnum
{
A,
B = 20
}
И _DerivedEnum.C – 22:
enum _DerivedEnum
{
C = 22,
D,
E
}
Получим такой генерируемый код:
public enum DerivedEnum
{
A,
B = 20,
C = 22,
D,
E,
}
Метод расширения ToBaseEnum(...) также будет обновляться так, чтобы показывать исключение только тогда, когда мы пытаемся увеличить целое значение области DerivedEnum до 20:
public static BaseEnum ToBaseEnum(this DerivedEnum fromEnum)
{
int val = ((int)(fromEnum));
string exceptionMessage = "Cannot convert DerivedEnum.{0} value to BaseEnum - there is no matching value";
if ((val > 20))
{
throw new System.Exception(string.Format(exceptionMessage, fromEnum));
}
BaseEnum result = ((BaseEnum)(val));
return result;
}
Обратите внимание, что изменив значение первого поля суб-перечисления на меньшее или равное последнему полю супер-перечисления, генерация кода не осуществится, и это состояние будет отображаться, как ошибка. Например, попробуйте изменить значение _DerivedEnum.C на 20 и сохранить изменения. Файл DerivedEnum.extension.cs будет отображаться в списке ошибок.
Примечания о введении генератора объектного кода.
Код ввода кода генерирования содержится в схеме NP.DeriveEnum. Основная схема NP.DeriveEnum была создана с помощью шаблона "Visual Studio Package" (также, как это было сделано при Implementing Adapter Pattern и Imitating Multiple Inheritance в C# с использованием системы Roslyn, основанной на VS Extension Wrapper Generator).
Нам пришлось добавить пакеты Roslyn и MEF2, чтобы использовать функции Roslyn при таких командах, как "Nu Get Package Manager Console":
Install - Package Microsoft.CodeAnalysis - Pre
Install - Package Microsoft.Composition
Класс main генератора называется DeriveEnumGenerator. Он вводит интерфейс IVsSingleFileGenerator. У интерфейса есть два метода - DefaultExtension(...) и Generate(...). Метод DefaultExtension(...) позволяет разработчику указать расширение генерируемого файла:
public int DefaultExtension(out string pbstrDefaultExtension)
{
pbstrDefaultExtension = ".extension.cs";
return VSConstants.S_OK;
}
Метод Generate(...) позволяет разработчику указать код, который входит в состав созданного файла:
public int Generate
(
string wszInputFilePath,
string bstrInputFileContents,
string wszDefaultNamespace,
IntPtr[] rgbOutputFileContents,
out uint pcbOutput,
IVsGeneratorProgress pGenerateProgress
)
{
byte[] codeBytes = null;
try
{
codeBytes = GenerateCodeBytes(wszInputFilePath, bstrInputFileContents, wszDefaultNamespace);
}
catch (Exception e)
{
pGenerateProgress.GeneratorError(0, 0, e.Message, 0, 0);
pcbOutput = 0;
return VSConstants.E_FAIL;
}
int outputLength = codeBytes.Length;
rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(outputLength);
Marshal.Copy(codeBytes, 0, rgbOutputFileContents[0], outputLength);
pcbOutput = (uint)outputLength;
return VSConstants.S_OK;
}
В данном случае генерация кода получена за счет метода GenerateCodeBytes (...).
protected byte[] GenerateCodeBytes(string filePath, string inputFileContent, string namespaceName)
{
string generatedCode = "";
DocumentId docId =
TheWorkspace
.CurrentSolution
.GetDocumentIdsWithFilePath(filePath).FirstOrDefault();
if (docId == null)
goto returnLabel;
Project project = TheWorkspace.CurrentSolution.GetProject(docId.ProjectId);
if (project == null)
goto returnLabel;
Compilation compilation = project.GetCompilationAsync().Result;
if (compilation == null)
goto returnLabel;
Document doc = project.GetDocument(docId);
if (doc == null)
goto returnLabel;
SyntaxTree docSyntaxTree = doc.GetSyntaxTreeAsync().Result;
if (docSyntaxTree == null)
goto returnLabel;
SemanticModel semanticModel = compilation.GetSemanticModel(docSyntaxTree);
if (semanticModel == null)
goto returnLabel;
EnumDeclarationSyntax enumNode =
docSyntaxTree.GetRoot()
.DescendantNodes()
.Where((node) = > (node.CSharpKind() == SyntaxKind.EnumDeclaration)).FirstOrDefault() as EnumDeclarationSyntax;
if (enumNode == null)
goto returnLabel;
INamedTypeSymbol enumSymbol = semanticModel.GetDeclaredSymbol(enumNode) as INamedTypeSymbol;
if (enumSymbol == null)
goto returnLabel;
generatedCode = enumSymbol.CreateEnumExtensionCode();
returnLabel:
byte[] bytes = Encoding.UTF8.GetBytes(generatedCode);
return bytes;
}
Метод Generate (...) имеет доступ к C # в качестве одного из параметров. Мы используем такой способ, чтобы получить Id документа в системе Roslyn:
DocumentId docId =
TheWorkspace
.CurrentSolution
.GetDocumentIdsWithFilePath(filePath).FirstOrDefault();
Из документа Id можно получить идентификатор схемы, используя dockId.
Из схемы Id получаем Roslyn Project от Rosly Workspace:
Project project = TheWorkspace.CurrentSolution.GetProject(docId.ProjectId);
Из Project получаем следующее:
Compilation compilation = project.GetCompilationAsync().Result;
Также получаем Roslyn Document:
Document doc = project.GetDocument(docId);
С данного документа получаем Roslyn SyntaxTree:
SyntaxTree docSyntaxTree = doc.GetSyntaxTreeAsync().Result;
С компиляции Roslyn и SyntaxTree образовывается семантическая модель:
SemanticModel semanticModel = compilation.GetSemanticModel(docSyntaxTree);
Вы также получите синтаксис перечисления в файле SyntaxTree:
EnumDeclarationSyntax enumNode =
docSyntaxTree.GetRoot()
.DescendantNodes()
.Where((node) = > (node.CSharpKind() == SyntaxKind.EnumDeclaration)).FirstOrDefault() as EnumDeclarationSyntax;
Наконец, из SemanticModel и EnumerationDeclarationSyntax Вы можете вытянуть INamedTypeSymbol, соответствующий перечислению:
INamedTypeSymbol enumSymbol = semanticModel.GetDeclaredSymbol(enumNode) as INamedTypeSymbol;
INamedTypeSymbol очень похож на System.Reflection.Type. Практически всю информацию про тип С# можно получить от объекта INamedTypeSymbol.
Метод расширения DOMCodeGenerator. CreateEnumExtensionCode() генерирует и возвращает весь код.
generatedCode = enumSymbol.CreateEnumExtensionCode();
Другая часть кода, отвечающая за код генерации, входит в состав NP.DOMGenerator. Система Roslyn используется только для анализа, для генерации кода используется CodeDOM, так как он меньше по объему и удобнее.
Есть два основных статических класса в программе NP.DOMGenerator: RoslynExtensions - для анализа Roslyn и DOMCodeGenerator - для генерирования кода, используя функции CodeDOM.
Источник: http://www.codeproject.com/Articles/879129/Implementing-Enumeration-Inheritance-using-Roslyn
SQL. Нормальні стосунки
Автор: Станіслав Зуйко
Введение
В данной статье речь пойдет о такой части теории проектирования реляционных баз данных, как нормализация. Но для начала уделим немного внимания основным понятиям и самой сути реляционной теории, и вот почему:
в представлении многих термин «реляционная» в контексте баз данных означает то их свойство, что таблицы существуют не сами по себе, а связаны (от англ. «relation» – связь, соотношение) между собой (с помощью ключей).
На самом деле это не так, данный термин происходит от математического термина «relation» (отношение) и означает представление множества́ в теории множеств. В реляционной модели отношение – это множество связанных между собой данных, которые в базе данных реализуются в виде таблицы.
Мы отождествляем понятия отношения и таблицы, кортежи называем строками, атрибуты – столбцами. Кристофер Дейт (один из ведущих специалистов в области реляционной модели данных) называет эти понятия «дружественными», но отнюдь не равными и приводит пример с картиной художника Рене Магритта «Вероломство образов».
Надпись на картине гласит – «Это не трубка». И действительно, картина с изображением трубки – это не сама трубка, а её образ.
Точно так же таблица SQL – это не отношение, а лишь удачное изображение отношения. SQL (с null типами, которым не место в теории множеств и пр.) – это не реляционная модель в чистом виде, а лишь ее реализация. Поэтому из всех определений термина «нормализация» более всего мне нравится следующее – это использование SQL в реляционном духе.
В классической теории множеств по определению любое множество состоит из различных элементов. Отношение состоит из множества кортежей (кортеж (строка) – множество пар «атрибут : значение»; атрибут (поле, столбец) – свойство некой сущности; домен – множество допустимых значений атрибута). Таким образом, в отношении нет одинаковых кортежей, порядок следования кортежей и атрибутов не определен. Из этого следует, что отношения (не таблицы) всегда нормализованы (точнее, находятся в первой нормальной форме).
Первая нормальная форма (1НФ)
Каждый кортеж отношения содержит единственное значение соответствующего типа (домена) в позиции любого атрибута. Или, проще говоря, в табличном представлении отношения на пересечении любой строки и любого столбца мы видим только одно значение.
Допустим, у нас есть предприятие по доставке пиццы. Мы собрали все факты о заказах и у нас получилась следующая таблица:
Атрибут Order содержит несколько повторяющихся значений, наверняка, домен данного атрибута должен состоять из множества товаров из меню пиццерии (но никак не из множества списков товаров), а количество товара в заказе вообще относится к другому атрибуту. Также, в информации о заказчике (CustomerData) следовало бы выделить в отдельный атрибут номер телефона, причем у мистера Cheng Tsui их два.
После данных замечаний мы бы могли переделать таблицу под следующий вид:
Конечно же, следовало бы еще разделить наши Product1, Product2, Product3 на товар (beer, pizza и т.д.) и название товара (Papperoni , Veggie, SA и т.д.), а объем бутылки (0,5), который я вообще удалил, тоже определить в отдельный атрибут. Но основная проблема в этой таблице – это наличие переменного количества столбцов под продукт. И если с телефонами это не так критично (мы не будет хранить более двух номеров одного клиента), то с продуктами в одном заказе дела обстоят иначе. Конечно же, такие повторяющиеся атрибуты (отличаются только названием, но не доменом) не вписываются и в реляционную модель; от повторения кортежей (строк) нас избавит наличие атрибута OrderNo (ведь один клиент в один день может сделать идентичный заказ и ему его доставит, допустим, тот же курьер), который выступает явным претендентом на первичный ключ.
В общем, возвращаемся к тому, что таблицу нужно изменить, да и вообще, наверное, пора задуматься о том, что было бы неплохо ее разбить на несколько таблиц. Но пока что мы её модифицируем в следующий вид:
Здесь мы ввели дополнительный атрибут OrderItem, и теперь наш атрибут OrderNo не может уникально идентифицировать строку, похоже, наш первичный ключ будет составным (OrderNo, OrderItem). Пора бы перейти ко второй нормальной форме.
Стоп! А как же атомарность значений?
Атомарные данные – это данные, разделенные на наименьшие значения, дальнейшее деление которых невозможно или нецелесообразно. Например, атрибут Customer можно разбить на Фамилию и Имя, из Customer Address выделить улицу, дом, квартиру и так далее.
По этому поводу среди специалистов существует спор, стоит ли данное понятие включать в нормализацию и вообще уделять ему внимание. Конечно же, атомарность упрощает контроль над правильностью данных в таблице (определение более четкого домена, например, номерами домов должны быть только целые положительные числа), но, с другой стороны, это не должно быть панацеей. Допустим, наша пиццерия находится в небольшом городе, мы не планируем собирать статистику заказов по улицам (например, для принятия решения об открытии нового отделения на улице с наибольшим количеством продаж), а единственным пользователем данной информации (поле Customer Address) будет курьер и ему вполне приемлемо видеть адрес целиком. При необходимости, мы всегда сможем написать и такое выражение для выборки:
SELECT * FROM Orders
WHERE [Customer Address] LIKE '%Shevchenko%'
Вторая нормальная форма (2НФ)
Если у Вас несоставной первичный ключ, переходите к третьей нормальной форме.
Вторая нормальная форма начинает избавлять нас от избыточности данных (дублирования) в той части, что в таблице не должно быть неключевых столбцов, которые функционально не зависят от всего первичного ключа.
В нашем случае целый ряд атрибутов не зависит от части ключа – столбца OrderItem: Date, Customer, Customer Address, телефоны, Courier. Пора таблицу разбить на несколько (Customers, OrderInfo, Orders):
Третья нормальная форма (3НФ)
Мы уже пришли к первой и второй нормальным формам и пора задуматься о третьей, которая связана с транзитивными зависимостями. Данная зависимость возникает тогда, когда неключевой атрибут зависит от первичного ключа не напрямую, непосредственно, а транзитивно, т.е. через другой неключевой атрибут. Такого быть не должно. Наверняка, в базе данных нашей пиццерии есть таблица о сотрудниках: уже знакомые нам курьеры, а также телефонные операторы, повара, директор и другие. Пусть данная таблица содержит информацию о должностях и окладах:
Первичный ключ – на поле Employee Name. Поле Salary зависит от поля Employee Name (PK) транзитивно (через поле Position). Проще говоря, оклад зависит от должности (напрямую), а не от имени (конечно же, при условии, что по существующей бизнес-логике оклад действительно определен на каждую должность, а не на отдельного сотрудника, т.е. не может быть двух курьеров с разными окладами). Следует разделить таблицы.
Нормальная форма Бойса-Кодда (BCNF)
Данная нормальная форма расширяет 3НФ, естественно, подразумевает предварительное приведение к 3НФ и не должно быть других потенциальных первичных ключей, иными словами – не должно быть зависимости атрибутов первичного ключа от других неключевых атрибутов.
Давайте вернемся к таблице OrderInfo. У нас есть составной первичный ключ по полям OrderNo, OrderItem, но мы могли бы сделать ключ и по полям OrderNo, ProductName. Нужно вынести информацию о продукте (поля Product, ProductName) в отдельную таблицу, добавить поле ProductId, которое будет ссылаться (FK) на таблицу с информацией о продуктах.
Существует еще 4НФ, 5НФ и даже 6НФ, но они почти не имеют практического применения и в данной статье рассматриваться не будут.
Пора сделать некие выводы и поговорить о значимости нормализации. Во-первых, мы избавляемся от избыточности данных, а значит – экономим память. Во-вторых, мы решаем проблемы обновления данных, исключаем связанные с этим возможные возникновения аномалий. В-третьих, упрощаем контроль целостности данных. В-четвертых, база данных более понятно описывает реальный мир и готова к дальнейшему расширению.
Факторизація цілих чисел
Автор: Редакция ITVDN
Введение
Факторизация целых чисел позволяет раскладывать на множители (факторинг) большие числа (Int64) и проверять простоту целых чисел [1,2].
Приведем пример больших (14 ... 18-ти значных) простых чисел, которые можно использовать для тестирования или оценки.
biggest 18-digit primes
999999999999999989
999999999999999967
999999999999999877
biggest 17-digit primes
99999999999999997
99999999999999977
99999999999999961
biggest 16-digit primes
9999999999999937
9999999999999917
9999999999999887
biggest 15-digit primes
999999999999989
999999999999947
999999999999883
biggest 14-digit primes
99999999999973
99999999999971
99999999999959
Кодовый модуль демонстрирует практическое использование алгоритма, написанного в C# (4.0).
using System;
using System.Collections.Generic;
namespace Infosoft.MathShared
{
///
Integers: Properties and Operations
public static partial class Integers
{
#region Prime Numbers <100
private static readonly int[] Primes =
new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23,
29, 31, 37, 41, 43, 47, 53, 59,
61, 67, 71, 73, 79, 83, 89, 97 };
#endregion
// starting number for iterative factorization
private const int _startNum = 101;
#region IsPrime : primality Check
///
/// Check if the number is Prime
///
/// Int64
/// bool
public static bool IsPrime(Int64 Num){
int j;
bool ret;
Int64 _upMargin = (Int64)Math.Sqrt(Num) + 1;;
// Check if number is in Prime Array
for (int i = 0; i < Primes.Length; i++){
if (Num == Primes[i]) { return true; }
}
// Check divisibility w/Prime Array
for (int i = 0; i < Primes.Length; i++) {
if (Num % Primes[i] == 0) return false;
}
// Main iteration for Primality check
_upMargin = (Int64)Math.Sqrt(Num) + 1;
j = _startNum;
ret = true;
while (j <= _upMargin)
{
if (Num % j == 0) { ret = false; break; }
else { j = j + 2; }
}
return ret;
}
///
/// Check if number-string is Prime
///
/// string
/// bool
public static bool IsPrime(string StringNum) {
return IsPrime(Int64.Parse(StringNum));
}
#endregion
#region Fast Factorization
///
/// Factorize string converted to long integers
///
/// string
/// Int64[]
public static Int64[] FactorizeFast(string StringNum) {
return FactorizeFast(Int64.Parse(StringNum));
}
///
/// Factorize long integers: speed optimized
///
/// Int64
/// Int64[]
public static Int64[] FactorizeFast(Int64 Num)
{
#region vars
// list of Factors
List _arrFactors = new List();
// temp variable
Int64 _num = Num;
#endregion
#region Check if the number is Prime(<100)
for (int k = 0; k < Primes.Length; k++)
{
if (_num == Primes[k])
{
_arrFactors.Add(Primes[k]);
return _arrFactors.ToArray();
}
}
#endregion
#region Try to factorize using Primes Array
for (int k = 0; k < Primes.Length; k++)
{
int m = Primes[k];
if (_num < m) break;
while (_num % m == 0)
{
_arrFactors.Add(m);
_num = (Int64)_num / m;
}
}
if (_num < _startNum)
{
_arrFactors.Sort();
return _arrFactors.ToArray();
}
#endregion
#region Main Factorization Algorithm
Int64 _upMargin = (Int64)Math.Sqrt(_num) + 1;
Int64 i = _startNum;
while (i <= _upMargin)
{
if (_num % i == 0)
{
_arrFactors.Add(i);
_num = _num / i;
_upMargin = (Int64)Math.Sqrt(_num) + 1;
i = _startNum;
}
else { i = i + 2; }
}
_arrFactors.Add(_num);
_arrFactors.Sort();
return _arrFactors.ToArray();
#endregion
}
#endregion
}
}
Точки обзора
Тест на проверку простоты 18-ти значного числа (999999999999999989), т.е. процедура, которая определяет, являются ли целые числа простыми, это лучший способ проверки факторинга программного обеспечения. Если вычисления занимают слишком много времени (например, когда используется мобильная платформа с низким уровнем обработки большого количества численных данных), возьмите меньшее число, но тоже 18-ти значное: 324632623645234523.
Чтобы получить не такую тривиальную запись, как i = i + 2, или i + = 2, необходимо исходный код увеличить в два раза.
i ++; i ++;
Даный фрагмент кода был использован для сравнения производительности трех методов возрастания целых чисел:
using System;
using System.Diagnostics;
namespace IncrementEfficiencyTest
{
class Program
{
private const Int64 _max = 1000000000; // 1 billion
private const int _cycles = 5;
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
Console.Write("{0} on {1}", "i++;i++:", String.Concat(_cycles, " cycles with ", _max, " max: "));
sw.Restart();
for (int count = 0; count < _cycles; count++)
{
Int64 i = 0;
while (i < _max) { i++; i++; }
}
sw.Stop();
Console.WriteLine("{0} elapsed.", sw.Elapsed);
Console.Write("{0} on {1}", "i=i+2", String.Concat(_cycles, " cycles with ", _max, " max: "));
sw.Restart();
for (int count = 0; count < _cycles; count++)
{
Int64 i = 0;
while (i < _max) { i = i + 2; }
}
sw.Stop();
Console.WriteLine("{0} elapsed.", sw.Elapsed);
Console.Write("{0} on {1}", "i+=2", String.Concat(_cycles, " cycles with ", _max, " max: "));
sw.Restart();
for (int count = 0; count < _cycles; count++)
{
Int64 i = 0;
while (i < _max) { i += 2; }
}
sw.Stop();
Console.WriteLine("{0} elapsed.", sw.Elapsed);
Console.ReadKey();
}
}
Чтобы минимизировать потенциальные побочные эффекты теста, следует работать в нескольких циклах (5 циклов) с последующей апроксимацией нескольких результатов тестирования и не нужно реализовывать вызовы функций , потому что оценка синхронизации может искажаться. Основываясь на статистических данных, самый быстрый способ увеличения числа Int64 в 2 раза можно достичь через составленное уравнение: i = i + 2 (5,589 сек для всей процедуры тестирования), вместе с i + = 2 (5,625 сек) и удвоением и ++; i ++; "leading from behind" с оценкой производительности в 11,907 сек. Соответствующая поправка была сделана в факторизации первичных чисел (теперь выводится i = i + 2).
Параллельный алгоритм для факторинг-теста
При использовании параллельных алгоритмов факторизации можно значительно увеличить производительность теста.
Параллельне алгоритмы факторизации
region GetFirstFactorParallel(Int64 Num) algorithm
internal static Int64 GetFirstFactorParallel(Int64 Num)
{
// use concurrent stack to store non-trivial factor if found
ConcurrentStack _stack = new ConcurrentStack();
// object to specify degrees of parallelism
ParallelOptions _po = new ParallelOptions();
try
{
// return value initially set to 1
Int64 _ret = 1;
// step 1: try to factor on base 2, return if OK
if (Num % 2 == 0) return 2;
// step 2: try to factor on base 3, return if OK
if (Num % 3 == 0) return 3;
#region parallel algo to find first non - trivial factor if exists
// set upper limit
Int64 _upMargin = (Int64)Math.Sqrt(Num) + 1;
// number of CPU cores
int _countCPU = System.Environment.ProcessorCount;
// max degree of parallelism set equal to _cpuCount
_po.MaxDegreeOfParallelism = _countCPU;
Parallel.For(0, 2, _po, (i, _plState) = >
{
// starting number for inner loops (5 and 7)
int _seed = 5 + 2 * i;
// inner loops running in parallel;
// notice that because input Num was already tested for factors 2 and 3,
// then increment of 6 is used to speed up the processing,
// thus in dual core CPU it looks like:
// 5, 11, 17, 23, 29, etc. in first thread
// 7, 13, 19, 25, 31, etc, in second thread
for (Int64 j = _seed; j < _upMargin; j += 6)
{
// exit loop if stack contains value
if (_stack.Count != 0) { break; }
// check divisibility
if (Num % j == 0)
{
// push non-trivial factor to ConcurrentStack and exit loop
if (_stack.Count == 0) { _stack.Push(j); }
break;
}
}
});
#endregion
// return the value in ConcurrentStack if exists, or 1
return (_stack.TryPop(out _ret)) ? _ret : 1;
}
catch { throw; }
finally { _po = null; _stack = null; }
}
#endregion
Источник: http://www.codeproject.com/Tips/155308/Fast-Prime-Factoring-Algorithm
Хто такий Type Script?
Автор: Віталій Толмачев
Введение
Сегодня уже никого не удивишь выходом очередной новой технологии. Уж у нее точно будет та самая кнопка «Сделать все красиво за меня» и уж точно она будет работать как следует. Пользователи уже сравнительно спокойно относятся к выходу новых фреймворков и их освоению. Более того, даже с некоторой осторожностью. Где гарантия, что новенький всеумеющий фреймворк в обычный вторник через год не перестанут поддерживать, так как он не нашел своей широкой реализации и нужного комьюнити?
Если объективно оценивать ситуацию, то Java Script победил. На сегодняшний день это самый кроссплатформенный язык. Его можно спокойно разместить как внутри страницы
<script type="application/javascript">
alert('Hello, World!');
script>
Так и внутри тега
<a href="delete.php" onclick="return confirm('Вы уверены?');">
Удалить
a>Более
Более того, можно вынести в отдельный файл
<head>
<script type="application/javascript" src="http://Путь_к_файлу_со_скриптом">
script>
head>
Он отлично себя чувствует как на стороне клиента (браузер), так и на стороне сервера. И все равно, какую платформу использует клиент. Что уже говорить о браузерных операционных системах. В IndraDesktop WebOS программный код на 75 % состоит из JavaScript, IntOS — на 70 %, eyeOS — 5 %, но в eyeOS JavaScript участвует в визуализации на клиенте, что очень важно для отлаженной работы между клиентом и сервером.
Все Вы слышали о языке Java Script, а кто-то из Ваших друзей может внятно объяснить, что за ЯП такой Type Script? Кто создатель языка, какие особенности языка? Все очень просто. Человек, имея опыт создания Turbo Pascal, Delphi и даже С#, решил создать что-то еще лучше. Имя ему Андерс Хейлсберг. TypeScript представлен миру в 2012 году компанией Microsoft и был призван расширить возможности JavaScript. Код компилятора TypeScript распространяется лицензией Apache и на данный момент разработка данного языка ведётся в открытом репозитории GitHub.
Имея опыт разработки в строго типизированных языках, многим программистам поведение под кодом JS не всегда является очевидным. А что, если дать языку JS поддержку полноценных классов, статическую типизацию, поддержку подключения модулей? Станет ли код очевидным, облегчит ли это рефакторинг, поиск ошибок еще на этапе разработки? Наверно, с такими мыслями проснулся однажды Хейлсберг. Все это ему удалось реализовать в TypeScript. Видимо, ни для кого уже не секрет, что на выходе из компилятора TypeScript мы получим JS код. Но идея была настолько популярна и востребована, что ИТ сообщество моментом подхватило такую инициативу. Доказательством этого может послужить наличие дополнений для TS в Vim, Emacs и даже в Visual Studio. Более того, вместе с выходом спецификации TS файлы, которые бы помогли понимать статическую типизацию, уже были среди JS-библиотек, среди которых оказался даже jQuery.
Как же быть? TS неявно типизирован и в то же время поддерживает статическую типизацию. Если тип возвращаемого значения не указан, компилятор выберет type inference для вывода типа. Например, если в функцию сложения двух чисел мы передадим 2 типа numbers , то очевидно что возвращаемое значение будет также number.
function add(left: number, right: number): number {
return left + right;
}
Но как раз прописывание возвращаемого значения позволяет компилятору проверить правильность. В случае, если тип не может быть выведен из-за отсутствия объявления типа, тогда по умолчанию будет динамический тип any.
Так же используя компилятор для TypeScript, Вам будет доступна опция создания отдельного файла декларации (тайпинга). Он будет иметь расширение .d.ts. В данном файле останутся только сигнатуры методов. Это напоминает заголовочный файл header в С/С++
declare module arithmetics {
add(left: number, right: number): number;
subtract(left: number, right: number): number;
multiply(left: number, right: number): number;
divide(left: number, right: number): number;
}
Такие файлы уже написаны за нас как для библиотек JS (таких как jQuery, AngularJS), так и для Node.js, забрать их можно на GITHUB
Резюмируя все вышесказанное, можно сделать вывод, что язык TypeScript будет интересен, понятен и очевиден разработчикам, которые знакомы с объектно-ориентированными подходами, привыкшие к четкому пониманию, какой тип будет ожидаемым на определённом этапе выполнения инструкций. Тем, кто привык рефакторить свой код перед публикацией, а не собирать отзывы от клиента. У этого языка уж точно есть будущее!
Вступ до NUnit
Автор: Редакция ITVDN
Введение
Статья рассказывает об NUnit – открытой среде юнит-тестирования приложений для .NET. В данной статье мы рассмотрим, что такое NUnit, как его загрузить и установить, создание классов тестов , а также запуск теста.
NUnit - открытая среда юнит-тестирования приложений для .NET, которая позволяет создавать автоматические тесты. Даный вид тестов обладает рядом преимуществ:
Высокое качество программы;
Снижение стоимости;
Безопасность регрессии сети
Чем выше качество программы, тем меньше средств затрачивается на устранение недостатков проекта. То есть, если найти недостатки в проекте на раннем этапе, решить их будет дешевле.
Загрузка и установка NUnit
Вы можете скачать NUnit с сайта http://www.nunit.org/
После завершения загрузки, разархивируйте файл и запустите программу.
Создание проекта библиотечного класса
Теперь создадим простой класс теста, используя C#, который добавляет два показателя, и протестируем его. Чтобы создать тест класса в Visual Studio, используя С#, выполните следующие шаги:
Шаг 1: Создание проекта библиотечного класса
Откройте Visual Studio.
Для создания проекта библиотечного класса сначала нажмите File -> New -> Project, выберите Visual C # в установленном шаблоне, выберите Class Library. Введите подходящее название (мы используем IntroNUnitTest), нажмите "OK".
После того, как Вы кликнули кнопку "OK", Вы увидите Ваш проект в Solution Explorer (в правом верхнем углу Visual Studio).
Шаг 2: Добавьте ссылки к Вашему проекту.
Чтобы добавить ссылку NUnit к Вашему проекту, кликните правой кнопкой мыши на ссылку, выберите Add reference-> Browse, затем nunit.framework.dll и «OK».
Шаг 3: Создание тестового класса.
Кликните правой кнопкой мыши на Вашем проекте, выберите Add -> Class, введите имя (используем MyNUnitTestClass) и далее "Add".
После того, как Вы кликнули на кнопку Add, Вы увидите класс.
После того, как Вы создали класс, добавьте using NUnit.Framework.
Следует соблюдать некоторые условия и понятия:
Каждый класс должен содержать атрибут [TestFixure] и должен быть общедоступен.
В каждом методе должен присутствовать атрибут [Test].
Оператор подтверждения об отсутствии ошибок: Булевские значения, описывающие, что должно быть ключевым словом, когда выполняется действие.
Ожидаемое исключение: один из типов исключения, который мы ожидаем во время выполнения тест-метода.
Установка: программа, которая запускается перед выполнением каждого тест-метода (например, регистрация в системе конкретного пользователя или инициализация одноэлементных классов).
Демонтаж: программа запускается после окончания каждого тест-метода (например, удаление строк из таблицы, которые были вставлены во время теста).
На примере мы постараемся сравнить две переменные х и у. Каждой переменной присвоили значение 20. В общей сложности написали 4 теста (PositiveTest, NegativeTest, ExpectedExceptionTest и NotImplementedException).
Запуск тестов
После написания всех тестов в тестовом классе необходимо запустить тесты, чтобы проверить, проходят ли они успешно. Для запуска тестов перейдите в папку NUnit, выберите NUnit Application (.exe) и дважды кликнике по ней, выберите команду File-> Open Project, выберите проект (в нашем случае это IntroNUnitTest.dll), затем кликаем Run.
Далее Вы увидите количество тестов, которые не сработали, и количество невыполненных тестов.
Если Вы хотите запустить какой-то определенный тест, кликните правой кнопкой мыши в тесте, который Вы хотите запустить, и выберите Run test(s).
Другие настройки
Вы также можете использовать другие настройки для запуска тестов:
Testdriven.net
ReSharper Jetbrains
Источник: http://www.c-sharpcorner.com/UploadFile/18fc30/introduction-to-nunit-test-driven-development-using-nunit-a/
Гібридні мобільні програми - міф чи реальність? Частина друга 2
Автор: Дмитро Івченко
Структура Ionic проекта
Когда вы начинаете свой проект на Ionic, вы найдете множество файлов, которые могут ввести вас в непонимание происходящего.
Давайте взглянем на конфигурационные части проекта:
package.json пакеты для подгрузки NodeJS модулей
bower.json пакеты для подгрузки Bower модулей
config.xml все свойство для создания проекта Сordova
gulpfile.js описание для сборки проекта на GulpJS
Эти файлы являются основой для вашего Ionic проекта. Они не очень отличаются от любого другого AngularJS приложения.
Также у вас есть несколько папок:
hooks/ не очень важна в начале разработки, тут будут находиться специфические скрипты
plugins/ сюда будут установлены плагины cordova
www/ именно здесь будет происходить магия
Большую часть времени вы будете просто работать в WWW/ папке, поскольку код вашего приложения там. Почти всегда вы начнете с index.html и app.js внутри этой папки, которые выступают в роли позвоночника вашего приложения.
Базовая разметка
Когда вы работаете с Ionic, вся разметка будет в HTML файлах, что дает возможность создавать адаптивную верстку, это означает, что ваше приложение само подстроится под расширение экрана пользователя.
Базовая разметка выглядит следующим образом:
<body ng-app="myApp">
<ion-content>
<ion-nav-view>ion-nav-view>
ion-content>
body>
Этот код не очень отличается от HTML, но вам, возможно, потребуется время, чтобы привыкнуть к некоторым пользовательским тегам Ionic и AngularJS, которые упростят разработку.
Кроме HTML, у вас также есть некоторые файлы JavaScript, которые контролируют ваше приложение и могут изменить views. В Ionic легко иметь дело с различными размерами экрана. Разрабатывая это, вы удивитесь, как легко ваше приложение работает на всех видах устройств.
Навигация по вашему приложению
Давайте посмотрим, как все происходит в действии с Ionic. Эта секция имеет за цель показать вам основные точки в разработке.
Маршрутизация по приложению
Маршрутизация страниц происходит через states, которые сконфигурированы для URL-адресов. Это означает, что вы можете указать различные состояния: дочерние, абстрактные и так далее в ваших app.js, которые будут загружаться на ваш index.html внутри ionic-view:
$stateProvider
.state('tab', {
url: "/tab",
abstract: true,
templateUrl: "templates/tabs.html"
})
.state('tab.dash', {
url: '/dash',
views: {
'tab-dash': {
templateUrl: 'templates/tab-dash.html',
controller: 'DashCtrl'
}
}
})
Дополнительно можно установить файл шаблона, который принадлежит контроллеру.
Эту концепцию иногда сложно понять, но это, безусловно, очень хороший обзор всех возможных состояний вашего приложения.
Панель вкладок
Панель вкладок хорошо известна каждому разработчику и с states и Ionic это не трудно сделать:
<ion-tabs class="tabs-positive">
<ion-tab title="Home" icon-on="ion-ios-filing" icon-off="ion-ios-filing-outline">
ion-tab>
<ion-tab title="About" icon-on="ion-ios-clock" icon-off="ion-ios-clock-outline">
ion-tab>
<ion-tab title="Settings" icon-on="ion-ios-gear" icon-off="ion-ios-gear-outline">
ion-tab>
ion-tabs>
Запустив этот код на эмуляторе в браузере либо на телефоне, вы увидите то, что представлено на картинке выше. Также можно заметить, что картинки на нижней панели вкладок загружены тоже с помощью атрибута icon-on. Ionic уже имеет встроенную коллекцию картинок, ваша задача заключается только в выборе подходящей.
Боковое меню
Боковое меню, которое вы можете вытащить, сделав привычное для вас движение, и без которого нельзя обойтись в многофункциональном приложении, создается с помощью указания, с какой стороны вы хотите спрятать данное меню.
Так будет выглядеть его общий код:
<ion-side-menus>
<ion-side-menu-content ng-controller="ContentController">
ion-side-menu-content>
<ion-side-menu side="left">
ion-side-menu>
<ion-side-menu-content>
ion-side-menu-content>
ion-side-menus>
function ContentController($scope, $ionicSideMenuDelegate) {
$scope.toggleLeft = function() {
$ionicSideMenuDelegate.toggleLeft();
};
}
Вот так выглядит боковое меню на одном из приложений. Довольно красиво, не правда ли?
А ведь для создания такого меню вам потребуется написать не более 30 строчек кода.
Styling/CSS
Одним из главных преимуществ является то, как в считанные секунды вы можете присваивать вашим элементам на странице CSS классы, и это не вспоминая основ каскадных таблиц стиля.
Перейдем к примерам:
Bar-positive создаст на странице заголовок синего цвета. Для этого всего-то нужно дописать в div класс “bar bar-header bar-positive”. Зарезервированные слова для цвета и сам цвет были выбраны создателями, исходя из самых распространенных и приятных для глаза расцветок. Но если вам понадобится изменить его на какой- то другой, то это также легко сделать.
Выводы
Как видим, у разработчиков Ionic получилось довольно хорошо реализовать приятную среду для создания кросплатформенных мобильных приложений. Все, что вам нужно - это установить эти фрейворки себе на ноутбук и создать базовый проект. Запустить его на каком-либо устройстве. А потом собрать это под необходимые платформы. Результаты поразительны, когда у вас есть то же самое приложение на Android и IOS устройствах.