У приложения есть стандартные кнопки свернуть и закрыть. Но меня они не устраивают. Нужно сделать свои кнопки. Поставил задачу сделать кнопки с прозрачным фоном. Должно выглядеть так:
А при наведении курсора цвет фона и значка менялся:
Начал делать реализацию так: Однако, так как я новенький в wpf, у меня возникло несколько вопросов:
Нет ли более простого способа, чем рисовать крестик и палку кодом? Может эти кнопки уже есть?
Как выполнить изменения стиля сразу 2-ух объектов? В интернете есть примеры с изменением цвета фона кнопки при наведении, однако те примеры с наведением на кнопку. У меня же наведение может коснуться самого значка на кнопке и не факт, что указатель будет находиться за кнопкой.
Правильно ли я вообще начал реализовывать это дело. Помещать кнопку и значок в grid?
Я не жду, что кто-то сделает готовый пример (хотя был бы очень признателен реализованному простому способу). Мне главное, чтобы натолкнули на верный путь, пояснив вопросы.
Ответ
Для начала, всё не проще, а сложнее. Если просто нарисовать кнопки, то они не попадут в non-client area. Поэтому вы должны поместить их туда, используя WindowChrome, например, как описано в этом вопросе: WPF Создание кастомного стиля окна с тенью Затем, по поводу отрисовки крестиков. Нет, в WPF нету встроенного крестика, потому что он для каждой системы свой (посмотрите, как выглядит он на Windows 7, и как на Windows 10), а также зависит от системных настроек (выбранной цветовой схемы, включенного или нет режима увеличения и/или повышенной контрастности и т. д.). Одна строчка нарисованного руками крестика — не слишком сложное требование. Я бы тем не менее поместил крестик внутрь кнопки, и подменил шаблон:
Оффтопик: Вы, судя по коду, пишете XAML через визуальный редактор. Это приводит к достаточно неоптимальному коду, и выводит из игры layout manager. (Например, вы размещаете кнопку на экране конструкциями наподобие Margin="382,10,23,0". Не делайте так, используйте layout manager вручную.)
Пытаюсь разобраться в написании собственных коллекций (да и вообще по глубже разобраться в коллекциях). Я сейчас в учебных целях пишу реализацию коллекции, которая наследует интерфейс ICollection. Такой вопрос, как должен себя вести метод add если в коллекции по умолчанию задано IsReadOnly = true? Есть такие варианты как:
выбрасывать исключение если он был вызван (но это ужасно глупо);
не иметь ни какой реализации (получается метод пустышка только для интерфейса, я не уверен, что это нормально);
скрывать его под явной реализацией интерфейса и делать реализацию пустой (то же самое, что и в предыдущем варианте только может чуть лучше).
Ответ
Именно так, бросать исключение. Ничего глупого в этом нет: если операцию невозможно выполнить, нужно как можно громче заявить об этом, а не притворяться, что всё идёт как надо. В противном случае программист добавит элементы в коллекцию, не заметит ошибку, и будет считать, что ничего странного не происходит. Отловить логическую ошибку («я добавил элементы в коллекцию, но они там не появились») на порядок сложнее, чем поймать креш в виде необработанного исключения. Наличие свойства IsReadOnly — ошибка в проектировании, сделанная ещё во времена .NET 1.0. Правильнее было бы иметь отдельный интерфейс IReadOnlyList (который появился в .NET 4.5).
Зачем в Java нужен модификатор native и для чего в классе Object некоторые методы помечены им?
Ответ
native указывает, что метод реализуется не в Java коде. В связке с JNI (Java Native Interface) идёт. Как правило, подразумевается, что метод реализован в c коде. Работа с диском, сеть и т.п. реализованы в Си части, и Java обёртки вызывают эти методы. Под рукой сейчас только Ubuntu. Пример на ней покажу. Есть у вас основной Java файл Main.java public class Main {
public native int intMethod(int i);
public static void main(String[] args) {
System.loadLibrary("Main");
System.out.println(new Main().intMethod(4));
}
}
И c файл Main.c #include
#include "Main.h" JNIEXPORT jint JNICALL Java_Main_intMethod (JNIEnv *env, jobject obj, jint i) {
return i * 2;
}
Ещё Makefile для сборки: .PHONY: all clean all:
javac Main.java
javah -jni Main
gcc -shared -fpic -o libMain.so -I$${JAVA_HOME}/include -I$${JAVA_HOME}/include/linux Main.c
java -Djava.library.path=. Main clean:
rm -f *.class *.so Main.h
Запустим всё это дело: javac Main.java
javah -jni Main
gcc -shared -fpic -o libMain.so -I${JAVA_HOME}/include \
-I${JAVA_HOME}/include/linux Main.c
java -Djava.library.path=. Main
На экране увидите: 8 Предварительные настройки:
Установлен jdk, самой собой.
Установить essential: sudo apt-get install build-essential
Путь прописать до Java. У меня это export JAVA_HOME='/usr/java/jdk1.8.0_131'
Пример показывает, как из Java вызвать Си код и вернуть результат. Когда это надо?
OS зависимые вещи.
Какие-то сложные вычисления. Часто математические библиотеки написаны на Си.
Как сделать такой же эффект как здесь? Особенно видно на слайде "loftec"? Попробовал сделать подобное, но у меня при наклоне картинки видно белый фон, а у них ощущение, что картинка огромная и по ней курсор ходит.
$('.test').tilt({
maxTilt: 2,
perspective: 500,
});
.test {
height: 100vh;
width: 100%;
background: url(https://i.ytimg.com/vi/oZa_djYJr4E/maxresdefault.jpg);
}
Ответ
Создаем контейнер для трансформируемого блока
Ставим этому контейнеру transform: scale(...), потому как плагин tilt трансформирует сам этот объект переназначая инлайново значения transform
Самому блоку (если это бэкграунд) ставим background-size: cover
Находим нужного качества и размера картинку, которая всё это будет терпеть
Чтобы эффект параллакса в Tilt не слетал, добавляем параметр reset: false
$('.test').tilt({
maxTilt: 2,
perspective: 500,
reset: false //Не возвращает параллакс на исходное "нулевое" значение
});
.test-container {
transform: scale(1.35);
}
.test {
height: 100vh;
max-width: 100%;
background: url(https://i.ytimg.com/vi/oZa_djYJr4E/maxresdefault.jpg);
background-size: cover
}
Надо сделать, чтобы при подключении определенной флешки запускалась программа. В интернете пишут, что можно через планировщик, но никто не пишет, как именно.
Ответ
Я слегка слукавил, без планировщика не обойтись, хотя, наверное, можно и через автозагрузку решить всё это. Я для одного пожилого сотрудника когда-то использовал вот такой скрипт, который срабатывал, если вставлялась флэшка, автоопределяемая с буквой T и меткой "BP_flahka". Если буква диска не важна, то вместо if ($driveLetter -eq 'T:' -and $driveLabel -eq 'BP_flashka') можно использовать просто if ($driveLabel -eq 'ТутМеткаВашейФлэшки'). Код скрипта: #Requires -version 2.0
Register-WmiEvent -Class win32_VolumeChangeEvent -SourceIdentifier volumeChange
write-host (get-date -format s) " Beginning script..."
do{
$newEvent = Wait-Event -SourceIdentifier volumeChange
$eventType = $newEvent.SourceEventArgs.NewEvent.EventType
$eventTypeName = switch($eventType)
{
1 {"Configuration changed"}
2 {"Device arrival"}
3 {"Device removal"}
4 {"docking"}
}
write-host (get-date -format s) " Event detected = " $eventTypeName
if ($eventType -eq 2)
{
$driveLetter = $newEvent.SourceEventArgs.NewEvent.DriveName
$driveLabel = ([wmi]"Win32_LogicalDisk='$driveLetter'").VolumeName
write-host (get-date -format s) " Drive name = " $driveLetter
write-host (get-date -format s) " Drive label = " $driveLabel
# Запустить, если буква диска и метка совпали с нужными значениями
if ($driveLetter -eq 'T:' -and $driveLabel -eq 'BP_flashka')
{
write-host (get-date -format s) " Starting task in 3 seconds..."
start-sleep -seconds 3
start-process "E:\sync.bat"
}
}
Remove-Event -SourceIdentifier volumeChange
} while (1-eq1) #Идём в цикле дальше
Unregister-Event -SourceIdentifier volumeChange
Дальше всё просто. В планировщике создаём новое задание, с такими параметрами:
Триггер: At log on
Действие: Start a program
Program/script: powershell
Аргументы: -WindowStyle Hidden -ExecutionPolicy Unrestricted -File "Диск:\Путь\имя файла со скриптом.ps1" Update 1. Проверок для вставляемого хранилища можно устроить массу. Например: # узнаем тип файловой системы флэшки
$fileSystem = ([wmi]"Win32_LogicalDisk='$driveLetter'").FileSystem
# проверяем, сколько свободного места осталось (в байтах) на флэшке
$freeSpace = ([wmi]"Win32_LogicalDisk='$driveLetter'").FreeSpace
# или общий размер всей флэшки:
$size = ([wmi]"Win32_LogicalDisk='$driveLetter'").Size
# и так далее, а затем просто проверяем нужный нам параметр, например:
if ($fileSystem -eq 'NTFS')
{
# в этом случае бэкап можно делать одним большим файлом
}
# и так далее
Update 2. Работать будет, начиная с Windows Vista/Server 2008
У меня есть набор изображений для обучения: для двух персон по 10 изображений и 80 изображений различных персон для проверки достоверности распознавания. Имеется 3 контрольных изображения, по 1 с каждой персоной и одна общая с десяткой персон (в которую входят первые две и несколько из 80). На всех изображениях персоны расположены фронтально. Хотелось бы в результате распознавания на всех 3 контрольных изображениях опознать две персоны, для которых производилось обучение с помощью 10 изображений.
Проблема заключается в том, что все 3 алгоритма (LBPH, Fisherfaces, Eigenfaces) не справились с этой задачой (на одном или двух изображениях помечают персону другой, причем для которой было всего 1 обучающее изображение), очевидно, у меня где-то ошибка в последовательности обучения или распознавания, или я чего-то не учел. Добавление изображения для обучения:
считать изображения для обучения в градациях серого
определить позицию лица и сделать новое изображение на основе этой позиции
для алгоритов кроме LBPH привести изображения к одному размеру (я так и не смог определить, какой лучше всего размер использовать, наугад тыкал разные)
Histogram Equalization
добавить в вектор который потом пойдет в обучение
Добавление изображения для распознавания:
Определить все лица на изображении в градации серого и для каждого выполнить
сделать новое изображение на основе позиции
для алгоритов кроме LBPH привести изображения к одному размеру
Histogram Equalization
отправить на распознавание
Буду рад принять любые советы и ответить на Ваши вопросы, спасибо за помощь!
Ответ
Процесс распознавания лица можно разбить на 3 стадии:
выделение области с лицом
нормализация изображения
сравнение и анализ
OpenCV предоставляет утилиты для 1 и 3 стадии, а вот 2 стадию (самую сложную) возлагает ответственность на пользователя.
Алгоритмы LBPH, Fisherfaces, Eigenfaces достигают 90% точности распознавания на специально подготовленных изображениях (нормализованных). Если взять подборку AT&T, то можно заметить, что у них все изображения: имеют одинаковый размер (ширина и высота), все приведены к градации серого с нормализацией, однотонный фон, лица отцентрированы и произведено выравнивание на основе опорных точек и произведены другие методы нормализации. Пример выполнения процесса нормализации. Разбор и анализ алгоритмов распознавания, используемых в OpenCV. AT&T Facedatabase Таким образом, проблема низкой точности распознавания в моем случае заключалась в том, что изображения имели низкий уровень нормализации. Для повышения уровня точности нужно либо добавлять различные алгоритмы для нормализации изображений, либо использовать для распознавания более современные алгоритмы, основанные на нейронных сетях и машинном обучении После нормализации на основе алгоритма из статьи существенно увеличилась точность определения (я добавил поворот и масштабирование изображения на основе положения глаз).
Как правильно расставить приоритеты, в какую сторону плыть? Наверное каждый программист, который только начитает изучать JAVA на уровне WEB разработки, задавался подобными вопросами.
Я начинающий JAVA программист, который пытается перешагнуть с SE в EE технологии. Но в большом потоке информации иногда тяжело определится, что нужно именно Вам? Для каких целей применяются те или иные технологии? Поэтому я составил список вопросов, которые должны заинтересовать не только меня, но и всех начинающих разработчиков (извините, если на первый взгляд вопросы окажутся для кого-то примитивными). Со временем список будет расширяться.
Буду весьма благодарен Вашим ответам, желательно с примерами кода, на подобие: System.out.println(“Это хороший пример”), а вот это ………*... – плохой пример, он будет работать, но через ..опу!
Вопросы:
Какая разница между jsp и jspx. Когда и какую структуру применять? Как они связаны с html, xhtml, и xml? На сколько подобные подходы устарели или это используется везде?
Что такое jsf и как оно связано с jsp (jspx), и можно ли (нужно ли) применять то и другое одновременно?
Servlet – это основа и без них никуда? Или есть другие подходы?
Когда что применяют: Spring, Hibernate, Struts … (много других)? Насколько они упрощают жизнь и увеличивают скорость разработки?
Разница между JavaBeans и EJB. Есть ли у Вас пример кода, что такое JB, а что такое EJB?
Как правильно создавать архитектуру приложения, чтобы не запутаться в бесконечном коде? Какие инструменты Вы лично для этого используете (UML – или это не катит)?
Спасибо за Ваши ответы, буду очень благодарен за Ваши ссылки на некоторые небольшие WEB проекты простенькие для понимания (может Github или что-то другое).
Ответ
Ответы (упрощенно):
JSP и JSPX практически одно и то же. JSPX это XML совместимая версия JSP
JSF это стандартный Sun/Oracle фреймворк реализующий паттерн MVC, где JSP используется в качестве компонента View
Servlet это основа - без них реально никуда - это must have в багаже Java Web developer'а
Все зависит от целей разработки+предпочтений тим лидеров. Судя по всему вы начинающий девелопер, посему не забивайте себе голову. Старшие товарищи (работодатели или тим лидеры) тебе сами скажут работаем в таком то фреймворке - твое дело взять под козырек и выполнять.
JavaBeans - это грубо говоря Java объект имеющий стандартизованный интерфейс для работы с ним через т.н. геттеры и сеттеры. EJB - забудь это почти вымершая технология, если его и спрашивают то только для понтов. JB == JavaBeans
Займись в первую очередь паттернами. UML в топку.
Начинайте изучать в таком порядке:
JavaBeans
Java Reflection
Servlet
JSP/JSPX
Паттерны (в первую очередь MVC)
Struts
Hibernate
JSF
Spring
EJB (факультативно)
P.S. Не пишите никогда JAVA, а пишите просто Java - неверное именование языка наводит на размышления об уровне квалификации
Например, вокруг фонаря) ну, или иного объекта, думаю, многие из вас видели, как летают всякие насекомые около, светящейся в ночи, лампы. В общем, нужно как-то математически описать траекторию полета этих "светлячков", и добавить хаотичности, т.к. просто летать по кругу не очень-то и интересно) вот взять "светлячка", ему обязательно хочется коснуться, да и прям-таки обжечься об лампу, а то и вовсе сгореть бесследно, это уж как повезет) то есть, нужна живость данного алгоритма) хотя, на первых порах, я и от обычного полета по кругам не откажусь. Может у кого есть ссылки на нужную литературу или блогозапись, готовая к реализации идея, или просто подсказка? Всему буду рад)
Ответ
Где-то читал что навигационная система светлячков устроена так: они летят под определенным углом к источнику света (в идеале к Луне). В случае бесконечного далекого объекта это дает некую прямую линию, а если источник света близкий (фонарь, костер) то светлячки движутся по спирали и в конце-концов обжигаются и падают.
Мне кажется вполне себе алгоритм: надо задаться навигационным углом светлячка + его скоростью полета. В вырожденном случае, если навигационный угол равен 90 градусам, светлячок будет летать по кругу, если угол 0 градусов - будет лететь прямиком к свету. Легко можно добавить хаотичности: немного случайно менять навигационный угол в зависимости от скорости полета или что-нить такое.
Как реализовать галерею с изображениями, разными по ширине, но фиксированными по высоте? Необходимо, чтобы изображения сами распределялись и ужимались в зависимости от места в блоке div. Есть скрипт masonry, но там, как я понял, такая штука работает только по вертикали. Как примерно должно выглядеть, показано на рисунке:
Ответ
Можно подключить плагин который автоматически будет выводить фото Например: Демо 1, 2, 3, 4, 5 ... Там сверху есть ссылка ( CollagePlus jQuery Plugin Example ) где можно скачать плагин. Успехов.
По каким причинам большинство .net классов являются запечатанными (например: Int32, Double, String и т. п.)? Есть ли в каких книгах/статьях объяснение данного архитектурного решения от создателей платформы?
Ответ
Все классы, которые не поддерживают наследование от них, должны быть sealed. Чтобы класс поддерживал наследование от него, необходимо обдуманное архитектурное решение: нужно рассмотреть реальные сценарии, когда это требуется; продумать, какие члена будут перегружаться; как остальные части системы будут работать с унаследованными классами и так далее. Если все классы сначала делать незапечатанными, а потом думать, то велика вероятность, что от этого будет больше вреда, чем пользы: никакие реальные возможности добавлены не будут, программисты полезут в потроха класса и нагромоздят хаков. И все эти хаки придётся поддерживать, потому что обратная совместимость — это святое. Это значит, что реализация может быть закрыта для улучшений в будущих версиях. Если какой-то класс закрыт, это значит, что архитектор не нашёл нормальных сценариев наследования, которые оправдывали бы незапечатенность класса. Классы типа String и StringBuilder закрыты, потому что это открывает возможности для изменения реализации классов, производительность которых критична для системы. Например, раньше билдер работал по принципу List, теперь он реализован через связный список блоков, каждый из которых растёт как List. Если бы хоть одна деталь старой реализации просочилась в protected интерфейс, изменить её было бы невозможно. Если бы внутренняя реализация была закрыта, то наследование было бы абсолютно бесполезно: все операции и так были бы публичными. В этом случае достаточно статических методов (в том числе extension методов). Что касается Int32 и Double, то это вообще-то структуры, они вообще не поддерживают наследование. Логика разработчиков .NET описана в книге Framework Design Guidelines. Некоторые части книги доступны на MSDN
На этот вопрос отвечал Эрик Липперт в статье Why Are So Many Of The Framework Classes Sealed? Он называет один ключевой принцип: "Хороший код делает ровно то, для чего он создан, ни больше ни меньше", а затем раскрывает его:
Философский. Наследование основано на отношении is-a. Если нельзя придумать такой класс, то наследование запрещено.
Практический. Создавать классы, которые можно расширять, сложно.
Совместимость. Закрытый класс можно сделать открытым, но не наоборот.
Безопасность. Если с помощью наследования можно переопределить логику базового класса, можно исковеркать логику и подвергнуть систему угрозе.
Более развёрнутая аргументация по ссылке выше.
В целом, классы во фреймворке "по умолчанию" закрыты примерно по той же причине, почему методы в C# по умолчанию невиртуальны. Можно вспомнить Java с виртуальными по умолчанию методами и учиться на ошибках.
Имеется следующий код: int i = 2020202048;
i += 0.0f;
System.out.println(i);
Выводит: 2020201984 Почему?
Ответ
Проблема кроется в составном операторе присваивания +=. Согласно документации исходное выражение i += 0.0f; разворачивается в i = (int)(i + 0.0f);. Выражение в скобках будет иметь тип float, в котором исходное число 2020202048 не имеет точного представления и таким образом изменяется до 2020201984.0f, которое потом приводится снова к int Неочевидность кода в вопросе в первую очередь обусловлена именно неявным преобразованием int → float → int (о чем уже упоминалось в комментариях к вопросу), которое происходит при использовании += с разными типами аргументов.
Почему данный код не работает? #include
#include int main()
{
min(1, 2);
std::numeric_limits::max();
}
А данный работает? #include
#include int main()
{
min(1, 2);
(std::numeric_limits::max)();
}
Интересует больше второй пример. Что с точки зрения языка это означает?
Ответ
Проблема заключается в том, что некоторые специалисты придумали поместить в Windows.h два define для min и max. Но перед компиляцией всегда работает препроцессор. Он видит max (о namespace он ничего не знает) и пытается найти два аргумента у него. А их там нет... И ругается. Когда появляются скобки, парсер препроцессора не видит скобок () не пытается сделать подстановку. Код стает "ожидаемый". Второй вариант исправить проблему - добавить в список define такой - NOMINMAX Для любознательных. Внутри Windows.h есть такое #ifndef NOMINMAX
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif #ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#endif /* NOMINMAX */
в Майкрософте проблему знают, но трогать не будут:).
Если string является ссылочным типом, как и class, то почему у str1 и str2 разные значения? По идее обе переменных должны ссылаться на одну и ту же область памяти в куче, как country1 и country2 static void Main(string[] args)
{
Country country1 = new Country();
country1.x = 1;
country1.y = 2; Console.WriteLine("Country1 {0}, {1}", country1.x, country1.y); Country country2 = new Country();
country2 = country1;
country1.x = 3; Console.WriteLine("Country1 {0}, {1}", country1.x, country1.y);
Console.WriteLine("Country2 {0}, {1}", country2.x, country2.y);
///////////////////
string str1;
str1 = "123"; Console.WriteLine("Str1 {0}", str1); string str2;
str2 = str1;
str1 = "1234"; Console.WriteLine("Str1 {0}", str1);
Console.WriteLine("Str2 {0}", str2);
}
Ответ
У переменной значимого типа значение хранится в самой переменной. У переменной ссылочного типа в переменной хранится ссылка на некоторую область памяти, в которой в свою очередь хранится значение. Теперь о типе string, переменная такого типа хранит ссылку, но нюанс состоит в том, что выделенная память, на которую это ссылка указывает является неизменяемой, поэтому каждый раз когда вы проводите какие либо манипуляции со строкой вы, фактически создаете новый объект в памяти. И такие манипуляции затронут, только, непосредственно, ту переменную которая подверглась изменениям. Давайте рассмотрим ваш пример. string str1; //здесь вы создали переменную str1, но она еще ни на что не ссылается
str1 = "123"; //здесь в переменную str1 записывается адрес литерала "123"
string str2;
str2 = str1; //здесь мы записали в переменную str2, значение адреса литерала "123"
//который сохранен в переменной str1
str1 = "1234"; //а вот сейчас мы пишем в str1 ссылку на совершенно другой литерал
//а в str2 остается старое значение, так с этой переменной
//вы никаких манипуляций не проводили
Да, небольшое добавление. Если вы сделаете так: string str1 = "1234";
string str2 = str1;
string str3 = str1;
все три переменный будут ссылаться на одну область памяти, но любое изменение, любой из них не затронет остальные две, а просто породит еще одну строку. Подробней можно почитать, например:
Строки, неизменяемость и персистентность.
Типы значений и ссылочные типы
std::set обычно представлен бинарным деревом поиска. У него есть методы begin и end, которые позволяют получить минимум и максимум, а также lower_bound и upper_bound для бинарного поиска. А что если мне надо получить итератор, указывающий на элемент в середине сета (или один из них, если в нём чётное число элементов)? Есть ли эффективный способ сделать это (за O(log(size)) вместо O(size))? {1} => 1
{1,2} => 1 или 2
{1,2,3} => 2
{1,2,3,4} => 2 или 3 (но в ту же сторону от середины, что и с {1,2})
{1,312,10000,14000,152333} => 10000
PS: Этот вопрос на английском.
Ответ
Или, если все-таки использовать set, то можно поддерживать итератор, указывающий на медианный элемент и число элементов k до этого итератора.
Изначально set пустой, итератор равен set.end(), k равно нулю
При добавлении элемента в set:
новый элемент больше медианного => при необходимости (если k * 2 + 3 <= set.size()) сдвигааем итератор на один вперед и увеличиваем k на единицу.
новый элемент меньше медианного => при необходимости сдвигааем итератор на один назад и уменьшаем k на единицу.
При удалении элемента из set действуем аналогично, при необходимости двигаем итератор на единицу вперед/назад
Таким образом, в любой момент времени у нас есть итератор на медианный элемент, дополнительные расходы для поддержания этого итератора составляют O(log n) на каждую операцию вставки/удаления
И еще вот полезный вопрос на английском Stack Overflow примерно про это же (там без удаления, но идея такая же)
Ведь лучше же. Переменные, которые влезут в диапазон -32768 - +32767 встречаются в коде часто. Short жрёт меньше оперативы, чем int. И почему-то всё равно почти не используют short. Почему?
Ответ
Когда говорят о размерности типа данных, то подразумевают скорее его диапозон допустимых значений, чем количество занимаемых байт в оперативной памяти. Большинство компиляторов выравнивает значения в памяти по некоторой границе (обычно по размерности регистров процессора). Соответственно значения типа short (при размерности 16 бит) и типа int (при размерности 32 бита) в итоге займут одинаковое количество байтов в памяти (например 4 или 8 байтов).
Более того, компиляторы и виртуальные машины знают о кэшах процессоров, и могут выполнять такую оптимизацию доступа к памяти, которая приведет к тому, что одно значение будет занимать целую линию кэша (например 32 байта).
Из этого можно сделать вывод, что экономия при выборе типа данных будет заметна при сохранении данных в бинарном виде (в виде массива байт в памяти или на диске), но слабо контролируется пользователем при размещении тех же данных в памяти как переменных.
Прошу прощения за большое количество текста. У Скита вычитал:
Methodlnvoker[] delegates = new Methodlnvoker[2];
int outside =0; // #1 Создает экземпляр переменной только однажды for (int i = 0; i < 2; i++)
{
int inside =0; // #2 Создает экземпляр переменной многократно
delegates[i] = delegate // #3 Захват переменной анонимным методом
{
Console.WriteLine ( " ({0 } ,{1}) " , outside, inside);
outside++;
inside++;
};
} Methodlnvoker first = delegates[0] ;
Methodlnvoker second = delegates[1]; first () ;
first () ;
first () ; second();
second(); Давайте подумаем, как это реализовано, по крайней мере, с компилятором С# 2 от
Microsoft. Происходит вот что: один дополнительный класс создается для содержания
переменной outer, а другой — для содержания переменной inner и ссылки на первый
дополнительный класс. По существу, каждая область видимости, которая содержит
захваченную переменную, получает собственный тип со ссылкой на следующую область
видимости, которая содержит захваченную переменную. В данном случае было два
экземпляра типа для содержания переменной inner, и оба они ссылаются на тот же
экземпляр типа, содержащий переменную outer.
То есть, если я правильно понял, в итоге создается нечто подобное:
class <>G1
{
int inside; // точнее, ссылка на inside
<>G2 outside;
} class <>G2
{
int outside
}
А теперь вопрос (если я правильно все понял) - зачем так делать? Почему нельзя сделать просто:
class <>G
{
int inside; // точнее, ссылка на inside
int outside;
}
Ответ
Отличный вопрос! Смотрите, в чём дело. Вот такой текст: class Program
{
delegate void MethodInvoker(); static void Main(string[] args)
{
MethodInvoker[] delegates = new MethodInvoker[2];
int outside = 0; // #1 Создает экземпляр переменной только однажды for (int i = 0; i < 2; i++)
{
int inside = 0; // #2 Создает экземпляр переменной многократно
delegates[i] = delegate // #3 Захват переменной анонимным методом
{
Console.WriteLine("({0}, {1})", outside, inside);
outside++;
inside++;
};
} MethodInvoker first = delegates[0];
MethodInvoker second = delegates[1]; first();
first();
first(); second();
second();
}
}
превращается компилятором C# в такой (я изменил имена для ясности; на самом деле, компилятор C# использует совершенно нечитаемые имена с запрещёнными для нас с вами символами для того, чтобы не было конфликтов): internal class Program
{
private delegate void MethodInvoker(); [CompilerGenerated]
private sealed class OuterScope
{
public int outside;
} [CompilerGenerated]
private sealed class InnerScope
{
public OuterScope outerLocals;
public int inside;
public void Method()
{
Console.WriteLine("({0}, {1})", outerLocals.outside, inside);
outerLocals.outside++;
inside++;
}
} private static void Main(string[] args)
{
// инициализация фрейма и его переменных
OuterScope outerScope = new OuterScope();
MethodInvoker[] delegates = new MethodInvoker[2];
outerScope.outside = 0; // было: outside = 0;
for (int i = 0; i < 2; i++)
{
// инициализация фрейма и его переменных
InnerScope innerScope = new InnerScope();
innerScope.outerLocals = outerScope;
innerScope.inside = 0; // было: inside = 0
delegates[i] = innerScope.Method;
} MethodInvoker first = delegates[0];
MethodInvoker second = delegates[1]; first();
first();
first(); second();
second();
}
}
(Посмотреть реальный код для текущей версии компилятора можно на sharplab.io.) Дело в том, что ссылки на переменные в .NET не могут быть полем класса (потому что экземпляр класса может пережить контекст, в котором определена переменная). Поэтому вместо этого все «захваченные» переменные превращаются в поля внутренних классов (OuterScope/InnerScope), а доступ к этим переменных превращается в доступ к полям объекта! Эти классы должны соответствовать блокам внутри программы: InnerScope создаётся каждый раз при входе в блок for, соответственно этому и его поля «видны» непосредственно только внутри этой итерации. Переменная outside должна быть одна и та же, и видна во всём методе Main, поэтому её нельзя «впихнуть» в объект InnerScope Видите?
Какой метод лучше использовать: #pragma once
или #ifndef XXX_H
#define XXX_H
...
#endif
Ответ
У обоих методов есть свои преимущества и недостатки.
#define кроссплатформенный, соответствует стандарту, поддерживается всеми компиляторами, но у него есть очевидный недостаток: если в проекте случайно найдутся два header-файла с одинаковым именем, необъяснимые ошибки гарантированы. Особенно неприятно это в случае больших проектов с 3rdparty-кодом. Можно придумать более продвинутую схему, при которой вероятность коллизии уменьшится (например, включать в guard полный путь к файлу в проекте или UUID), но гарантии вам никто не даст. (И вы не сможете потребовать от разработчиков посторонних библиотек следовать вашему стандарту.)
#pragma once лишено этих недостатков, потому что теперь ваше намерение прямо сообщается компилятору, а не посредством маломощного препроцесора. Но этот формат поддерживается не всеми компиляторами, поэтому наверняка будут проблемы с портируемостью.
Тем не менее, #pragma once поддерживается большим количеством компиляторов, так что если вы рассчитываете лишь на популярные компиляторы (MSVC, GCC, Clang, Intel compiler) свежих версий, имеет смысл остановиться на этом варианте. Имейте в виду, что многие опытные Unix-разработчики недолюбливают #pragma once, так что вам придётся обосновывать свой выбор.
Если ваш код есть часть какого-либо проекта, всё становится проще: просто спросите руководителя проекта о том, что рекомендуется к использованию. Выбор между include guard и #pragma once — часть coding standards любого проекта.
В различных источниках встречаются упоминания того, что нельзя использовать идентификаторы с несколькими подчеркиваниями, или что нельзя называть параметры шаблона _Ty
При этом заголовочных файлах стандартной библиотеки только такие имена и используются.
Почему так? Как надо писать правильно?
Ответ
C++ В главе Identifiers [lex.name] сказано, что некоторые идентификаторы зарезервированы, и могут быть использованы только компилятором и стандартной библиотекой:
зарезервировано любое имя, которое содержит двойное подчеркивание (__), или начинается с подчеркивания и следующей за ним большой буквой;
в глобальном пространстве имен, зарезервировано любое имя, которое начинается с подчеркивания.
В случае если эти правила нарушены, компилятор не обязан выдавать какие-либо ошибки или предупреждения, поведение программы не определено. Примеры: void _f(); // запрещено
class X {
int _m; // OK
int _M; // запрещено
};
namespace N {
int _1; // OK
void _f(); // OK
class X__Y; // запрещено
}
Почему так сделано? Это дает гарантию, что имена в стандартной библиотеке не будут пересекаться с пользовательским кодом. Например если написать #define X
struct Y;
#include то определение имен X и Y ничего не сломают в стандартных заголовочных файлах, и наоборот, если написать #include
struct X;
то никакие имена, определенные в стандартных заголовочных файлах не помешают определить X Также стандартная библиотека может использовать имена вида ::_f в своей реализации, тогда конфликт имен приведет к нарушению One Definition Rule, что обычно проявляется в виде ошибок линковки. C Аналогичные правила используются и в Си.
В главе "7.1.3 Reserved identifiers" приведен список зарезервированных идентификаторов:
все которые начинаются с _ и следующей за ним большой буквы или _
те которые начинаются с _ в области видимости файла, и находятся в обычном пространстве имен или пространстве имен тегов (в отличие от С++, разрешено двойное подчеркивание в середине и в конце имени);
имена макросов, приведенные в стандарте, если переопределение не разрешено явно;
имена с внешним связыванием, приведенные в стандарте, зарезервированы для имен с внешним связыванием;
имена из стандартных заголовочных файлов, если подключен соответствующий заголовочный файл.
void f(long long v) { cout << 1; }
void f(int v) { cout << 2; }
int main() {
long l = 2L;
f(l);
return 0;
}
Есть такой код, при этом ошибка компиляции - неоднозначность, а почему?! Cтандарт C++ гарантирует, что sizeof(int) <= sizeof(long) <= sizeof(long long)
И по правилам, расширение имеет больше приоритет чем стандартное преобразование. long в long long - расширение.
long в int - стандартное преобразование. Скорей всего повлияло, в моей модели данных long = int = 4, а long long = 8.
Какая тогда должна быть логика?
Если long = int, почему бы не выбрать функцию с int аргументом? Если я попробую заменить long l = 2L на int l = 2, все удачно скомпилируется, из за точного соответствия. PS: Все попытки на c++14
Ответ
Я не знаю, откуда вы взяли эту информацию о каком-то "расширении", которое якобы "имеет больше приоритет, чем стандартное преобразование". Язык С++ признает только два типа целочисленных преобразований при выполнении ранжирования неявных преобразований в процессе overload resolution. Это integral promotions и integral conversions (см. Table 12 в 13.3.3.1.2). Integral promotions - это преобразования, которым подвергаются "малые" целочисленные типы - [signed/unsigned] char и [signed/unsigned] short. Типы int, long и long long не могут подвергаться integral promotions, и к нашему случаю integral promotions никак не относятся. Все остальные преобразования между целочисленными типами являются integral conversions и имеют один и тот же ранг, независимо от того, являются ли они "расширяющими", "сужающими" или еще какими. В вашем случае преобразования long -> int и long -> long long являются integral conversions. Фактический размер типов на вашей платформе никакого значения не имеет. Ранжирование неявных преобразований полностью абстрагировано от этих размеров. Тот факт, что на вашей платформе int и long имеют одно и тоже физическое представление ничего не меняет. С точки зрения языка int и long - разные типы и между ними надо выполнять преобразования, пусть даже и чисто концептуальные. (Да, в С++ есть понятие сужающего (narrowing) преобразования, и преобразование из long в int в общем случае является сужающим, но при выполнении ранжирования неявных целочисленных преобразований этот момент не учитывается вообще.) В вашем случае обе функции-кандидата требуют integral conversion, т.е. преобразований одного и того же ранга. Значит вызов неоднозначен.
public static string StringToUCS2(string str)
{
UnicodeEncoding ue = new UnicodeEncoding();
byte[] ucs2 = ue.GetBytes(str); int i = 0;
while (i < ucs2.Length)
{
byte b = ucs2[i + 1];
ucs2[i + 1] = ucs2[i];
ucs2[i] = b;
i += 2;
}
return BitConverter.ToString(ucs2).Replace("-", "");
}
Все работает на ура! :)
Мониторинг файла. При изменениях в файле почему-то дважды запускается Change. Как можно это решить? Вот код: public void monitoring(string path)
{
this.sPath = path;
string first = Path.GetDirectoryName(path);
string second = Path.GetFileName(path);
FileSystemWatcher fsw = new FileSystemWatcher(first, second);
fsw.Changed += new FileSystemEventHandler(watcher_Changed);
fsw.EnableRaisingEvents = true;
} public void watcher_Changed(object sender, FileSystemEventArgs e)
{
MessageBox.Show("Be happy :3");
SplitAndQuery(this.sPath);
}
Ответ
Дело в том, что FileSystemWatcher опирается на уведомления от ОС. А запись изменений в файл далеко не всегда может являться атомарным действием: например, notepad.exe пишет на диск в несколько приемов, отдельно файл и отдельно его атрибуты, что повлечет за собой несколько срабатываний события Changed. Или при копировании/перемещении файлов запись происходит в несколько приемов. Избавиться от этого можно попробовать разными способами. Самый железобетонный, но не всегда подходящий -- отключать генерацию событий. Но пользоваться им надо аккуратно, т.к. можно пропустить другие полезные изменения. public void watcher_Changed(object sender, FileSystemEventArgs e)
{
watcher.EnableRaisingEvents = false;
try
{
MessageBox.Show("Be happy :3");
SplitAndQuery(this.sPath);
}
finally
{
watcher.EnableRaisingEvents = true;
}
}
Другой подход -- опираться на дату последней модификации файла (опционально еще и на e.ChangeType): DateTime lastWriteTime = DateTime.MinValue; public void watcher_Changed(object sender, FileSystemEventArgs e)
{
DateTime writeTime = File.GetLastWriteTime(this.sPath);
if (lastWriteTime != writeTime)
{
MessageBox.Show("Be happy :3");
SplitAndQuery(this.sPath);
lastWriteTime = writeTime;
}
}
Если файл изменяется не очень часто, а события приходят одно за другим, то можно использовать таймер с некоторым ожиданием и отсекать события, для которых не прошло нужное количество времени. В общем, выбор решения целиков зависит от ваших требований (впрочем, как обычно :)).
Хочу реализовать:
Button расположены квадратом (как 2-мерный массив NxN).
При клике на кнопку поворачиваются все кнопки в одной строке и в одном столбце.
Число N настраиваемое.
Начал сначала всё делать в MainWindow.xaml.cs, посоветовали всё сделать нормально и использовать MVVM. Код MainWindow.xaml.cs public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
} private Button[,] CreateButtons(int quantity)
{
Form.Rows = quantity;
Form.Columns = quantity;
Button[,] buttons = new Button[quantity, quantity];
for (int i = 0; i < quantity; i++)
{
for (int j = 0; j < quantity; j++)
{
buttons[i, j] = new Button();
buttons[i, j].Width = 100;
buttons[i, j].Height = 20;
buttons[i, j].Margin = new Thickness(5,80,0,0);
buttons[i, j].Click += new RoutedEventHandler(new_button_click);
}
}
return buttons;
} void new_button_click(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
if (btn != null)
{
var rotateTransform = btn.RenderTransform as RotateTransform;
var transform = new RotateTransform(90 + (rotateTransform == null ? 0 : rotateTransform.Angle));
transform.CenterX = 50;
transform.CenterY = 10;
btn.RenderTransform = transform;
}
} private void AddToWrapPanel(int quantity, Button[,] buttons)
{
for (int i = 0; i < quantity; i++)
for (int j = 0; j < quantity; j++)
{
Form.Children.Add(buttons[i, j]);
}
} private int GetQuantityButtons()
{
ComboBoxItem item = (ComboBoxItem)comboBox1.SelectedItem;
int count = int.Parse((string)item.Content);
return count;
} private void СreateButton_Click(object sender, RoutedEventArgs e)
{
if (Form.Children.Count > 0)
Form.Children.Clear();
int count = GetQuantityButtons();
Button[,] buttons = CreateButtons(count);
AddToWrapPanel(count, buttons);
}
}
Теперь начинаю всё переносить. XAML
Код VM public class MainWindowModel
{
public int Three { get; set; }
public int Four { get; set; }
public int Five { get; set; }
public int Six { get; set; }
public string Lvl { get; set; } public MainWindowModel()
{
Three = 3;
Four = 4;
Five = 5;
Six = 6;
Lvl = "Сложность (3 - 6):";
} private ICommand _seter; public ICommand Seter
{
get
{
return _seter ?? (_seter = new RelayCommand(() =>
{
// действие при вызове команды
}));
} } }
Пока только так.. Помогите, пожалуйста, перенести и доделать задуманные мной моменты. Например: как в VM, обслуживающем кнопку, завести свойство RotationAngle? Как при клике по "создать" с генерировать массив из кнопок и потом работать с ними? Как обращаться к UniformGrid и связать кол-во строк и столбцов с выбранным int в combobox?
Ответ
Давайте пойдём сначала. Построим VM. Нам пригодится базовый класс для VM, в котором будет имплементация INotifyPropertyChanged class VM : INotifyPropertyChanged
{
protected bool Set(ref T field, T value,
[CallerMemberName] string propertyName = null)
{
if (EqualityComparer.Default.Equals(field, value))
return false; field = value;
RaisePropertyChanged(propertyName);
return true;
} protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); public event PropertyChangedEventHandler PropertyChanged;
}
(Если вы пользуетесь каким-нибудь MVVM-фреймворком, то аналогичный базовый класс у вас уже может быть определён.) Теперь VM для одной клетки. Что нам нужно знать? Угол поворота — сделаем из него свойство с INPC. Строку и столбец — эти свойства неизменяемые. И команда, которая будет вызываться при активации клетки. (Она тоже неизменяемая.) Действие, которое будет выполняться при нажатии на клетку, сама клетка выполнить не может, так как поворот происходит у многих клеток. Поэтому реакцию на действие передадим «сверху» в качестве параметра. Получаем такой вот код: class CellVM : VM
{
public CellVM(int row, int column, Action onActivate)
{
Row = row;
Column = column;
Activate = new RelayCommand(() => onActivate(row, column));
} double rotationAngle = 0;
public double RotationAngle
{
get { return rotationAngle; }
set { Set(ref rotationAngle, value); }
} public int Row { get; }
public int Column { get; } public ICommand Activate { get; }
}
Следующая VM — вся доска. Ей придётся и принимать решение о вращении клеток. Какие нам тут нужны данные? Ширина и высота нужны, и при изменении нужно пересоздать массив клеток. Нужны сами клетки, и поскольку клетки у нас будут подменяться только как целое, берём не ObservableCollection, а просто IEnumerable. Наружу выставлять квадратный массив нельзя, никто не умеет к нему привязываться. Поэтому выставим все клетки, «слитые» в одну общую последовательность. class BoardVM : VM
{
int width;
public int Width
{
get { return width; }
set { if (Set(ref width, value)) { GenerateCells(); } }
} int height;
public int Height
{
get { return height; }
set { if (Set(ref height, value)) { GenerateCells(); } }
} CellVM[,] cells; public IEnumerable AllCells => cells.Cast();
Далее, при изменении количества строк или столбцов нам нужно перегенерировать клетки. void GenerateCells()
{
var cells = new CellVM[width, height];
for (int row = 0; row < height; row++)
for (int column = 0; column < width; column++)
cells[column, row] = new CellVM(row, column, OnCellActivate);
ShuffleAngles(cells);
// отбрасываем существующие клетки
this.cells = cells;
RaisePropertyChanged(nameof(AllCells));
}
... и установить им случайный начальный угол: static Random random = new Random();
void ShuffleAngles(CellVM[,] cells)
{
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
cells[x, y].RotationAngle = random.Next(4) * 90;
}
Теперь функция, которая вызывается при активации клетки. Нам нужно повернуть все клетки в том же столбце и той же строке. Во втором цикле пропускем уже один раз повёрнутую клетку. void OnCellActivate(int row0, int column0)
{
for (int row = 0; row < height; row++)
Rotate(cells[column0, row]); for (int column = 0; column < width; column++)
if (column != column0)
Rotate(cells[column, row0]);
} void Rotate(CellVM cellVM)
{
cellVM.RotationAngle = (cellVM.RotationAngle + 90) % 360;
}
}
Окей, с VM более-менее ясно. Переходим к View. Нам понадобится ItemsControl, т. к. мы хотим показать последовательность элементов. У нас последовательность элементов содержится в свойстве AllCells Далее, нам нужно, чтобы клетки укладывались в UniformGrid. Выберем в качестве носителя UniformGrid, заодно привяжем количество строк и столбцов: Дальше, как показывать отдельную клетку? Вы хотите Button, пускай. Пишем DataTemplate Запустив программу, видим, что кнопка слишком прилегает к границам клетки, поэтому даём ей Margin="10". Теперь, нам нужно как-то обозначить, где верх и где низ. Для этого нарисуем стрелочку вверх (но вам придётся сделать что-то покрасивее). Стрелочку будем поворачивать на угол из привязки: Вроде бы всё.
Теперь нужно ещё задать размеры поля. Для этого, по-хорошему, нужно завести другое окно (и показывать его только в самом начале игры), потому что изменять размер поля во время игры как-то неправильно. Но в нашем быстром прототипе мы закроем на это глаза. (А вам потом придётся таки переделать.) Итак, нам нужна информация о том, сколько у нас возможно строк и столбцов. Возвращаемся в VM и заводим класс: static class GameInfo
{
static public IEnumerable PossibleColumnNumber { get; } = new[] { 3, 4, 5, 6 };
static public IEnumerable PossibleRowNumber { get; } = new[] { 3, 4, 5, 6 };
}
Для красоты, нам нужно инициализировать значения в BoardVM валидным числом. Находим и меняем строки: int width = GameInfo.PossibleColumnNumber.Min();
и int height = GameInfo.PossibleRowNumber.Min();
Теперь View. Дописываем два комбобокса и метки к ним: Весь MainWindow.xaml Теперь нам нужно прикрепить VM к View. Лучше всего делать это не в XAML, а в App.xaml.cs (смотрите тут). Пишем: public partial class App : Application
{
BoardVM boardVM = new BoardVM(); protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
new MainWindow() { DataContext = boardVM }.Show();
}
}
и убираем из App.xaml StartupUri Компилируем, запускаем. Сразу видим пустое поле. Недоработка, мы ж не сгенерировали поле в конструкторе BoardVM! Исправляем: public BoardVM()
{
GenerateCells();
}
Вот что у меня получилось:
При попытке инициализации структуры через фигурные скобки вылезает ошибка:
error C2440: инициализация: невозможно преобразовать "initializer list" в "FunctionRelease"
struct FunctionRelease
{
std::string firstOperand;
std::string secondOperand;
Operation operation;
bool isTwoIdentifier = false;
};
... int main()
{
struct FunctionRelease functionRelease = { "v0", "v1", Operation::DIV, true };
}
В чём может быть причина?
Ответ
Инициализация экземпляра класса путём последовательного перечисления в фигурных скобках через запятую значений для полей этого класса, называется агрегатной инициализацией. Легко догадаться, что для возможности агрегатной инициализации требуется чтобы сам класс удовлетворял требованиям агрегата. Эти требования в последних стандартах звучат по-разному (выделение текста моё):
C++11
An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equalinitializers for non-static data members (9.2), no private or protected non-static data members (Clause 11),
no base classes (Clause 10), and no virtual functions (10.3)
С++14
An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or
protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).
Т.о. в более свежем стандарте ослабили требования к агрегатному типу, убрав необходимость отсутствия инициализации непосредственно в классе. Т.к. проблема проявила себя, значит был использован вариант c++11. И для решения достаточно убрать инициализацию члена isTwoIdentifier в классе.
Но если есть возможность скомпилировать код в режиме c++14, то никакие изменения вовсе не потребуются.
В данном скрипте на javascript сделан скрипт который выводит полный путь файла. Как исправить чтобы показывало только название файла?
Ответ
у инпутов с типом file есть коллекция выбранных файлов, в ней сохраняются объекты типа File, у которого есть поле name, в котором содержится имя выбранного файла.
document.getElementsByTagName('input')[0].onchange = function() {
if (this.files[0]) // если выбрали файл
document.getElementsByTagName('div')[0].innerHTML = this.files[0].name;
};
Как заметно, на данный момент это просто кривая, вогнутая в фигуру. Задача нарисовать полуокружность(или максимально приблизить к ней), вогнутую в фигуру.
В моём понимании для этого нужны less, sass и прочее. А также sin, cos. Плохо понимаю с чего и как начать, не сталкивался с этим.
Спасибо @AndreyFedorov за кусок его кода использованный здесь (!) согласен и на любые другие варианты, дающие такой же результат.
В c++17 появился новый синтаксис объявления переменных вида: auto [x, y, z] = f();
где f() - функция, возвращающая составной объект (массив, кортеж, структуру и т.п.). Как называется этот синтаксис и что он делает?
Ответ
Данная конструкция называется Structured binding declaration (Можно перевести как "объявление структурированной привязки") и позволяет объявлять сразу группу переменных (возможно даже разного типа) при наличии инициализирующего выражения. В качестве этого выражения в примере используется функция f Рассмотрим несколько примеров использования: #include
#include
#include
#include
Простой пример кода, попробуем отсортировать массив русских символов: var a = new char[]
{
'д',
'е',
'ё',
'ж'
};
var b = a.OrderBy(x => x).ToList();
Console.WriteLine(string.Concat(b));
Выдаст этот простой код неожиданное на первый взгляд дежё, но тут c# как раз верен стандартам, потому что код буквы ё больше, чем коды всех остальных букв русского алфавита. Попробуем отсортировать массив строк, одна из которых содержит букву ё var a = new string[]
{
"жар",
"дом",
"ели",
"ёлка",
};
var b = a.OrderBy(x => x).ToList();
Console.WriteLine(string.Join(" ", b));
Получаем ожидаемое дом ели ёлка жар. Вроде бы строки сортируются ожидаемым образом. Попробуем ели заменить на ель. Получим прекрасное дом ёлка ель жар. Очевидно, при сортировке строк е и ё считаются одним символом, во втором случае ёлка становится перед ель потому что к идёт раньше ь Моё наивное понимание предполагаемого алгоритма сортировки массива строк подсказывает, что он должен использовать тот же алгоритм сравнения кодов символов, что и сортировка массива символов. Этого, очевидно, не происходит. Ожидаемой модификацией алгоритма был бы учёт того, что ё в русском алфавите находится всё-таки не там, где она находится в unicode. А на самом деле имеем реализацию, где е и ё - это один символ. Меня интересует несколько вопросов. Где конкретно определён алгоритм сортировки строк? Мои путешествия по ReferenceSource увели меня куда-то в цппшные недра GitHub'а CLR, не уверен, что двигался верно. Почему было принято решение принимать е и ё за один символ, а не осуществлять честную сортировку? Это чьё-то волевое решение или это всё-таки определено в какой-то из спецификаций? Понимаю, что не все вопросы подразумевают наличие чёткого ответа у обычных участников сообщества, но ссылаюсь сюда А может быть, что я вообще всё интерпретировал неверно, поправьте в таком случае. Спасибо.
Ответ
Здесь причиной вашего удивления является не странность алгоритмов BCL, а имплементация стандарта Unicode. Документация стандарта Unicode Unicode® Technical Standard #10 /
Unicode Collation Algorithm гласит (перевод мой): 1.1 Многоуровневое сравнение
Сортировка, требуемая человеческими языками, сложна. Чтобы правильно её имплементировать, используется многоуровневый алгоритм сравнения.
При сравнении двух слов, самым важным являются базовые буквы, например, отличие между И и Е. Акценты обычно игнорируются, если базовые буквы не совпадают. Различие в регистре (прописные/строчные) также обычно игнорируются, если базовые буквы или их акценты различны.
Что делать с пунктуацией, зависит от обстоятельств. В некоторых ситуациях, точка или запятая считается как бы отдельной базовой буквой. В других ситуациях пунктуация игнорируется, если и так есть отличия в базовых буквах, акцентах или регистре.
В случае равенства иногда проводится финальное сравнение: если других различий нет, сравниваются (нормализованные) code point'ы.
Таким образом, сравнение слов проводится следующим образом:
Отбрасываются различия регистра и акценты. Если сравнение установило, какое из слов больше, конец алгоритма.
Возвращаются назад акценты, проводится повторное сравнение. Если сравнение установило, какое из слов больше, конец алгоритма.
Возвращается назад регистр, проводится повторное сравнение. Если сравнение установило, какое из слов больше, конец алгоритма.
и. т. д. Для русского языка по «принципу кроссворда» Ё считается акцентированным вариантом Е, а Й — акцентированным вариантом И Такой выбор стандарт для русского языка в Unicode, надеюсь, был согласован с лингвистами. Как это поменять в .NET — как заставить считать Ё отдельной буквой, расположенной между Е и Ж, я сходу не скажу. (Но смотрите соседний ответ.)
Кстати, имплементация того или иного стандарта Unicode — фича не языка, а системы. BCL просит систему сравнить строки, чтобы не дублировать имплементацию Unicode. Это значит, что одна и та же программа, будучи проинсталлированной на Windows 7 и Windows 10, может вести себя по-разному по отношению к сортировке.
Уточнение Для русской локали Й считается отдельной от И буквой, в то время как для английской Й считается акцентированным вариантом И. Буква Ё и там, и там считается акцентированным вариантом Е. Пример: var strings = new[] { "Иа", "Йокогама", "Италия", "Ель", "Ёлочка" };
var en = CultureInfo.GetCultureInfo("en-US");
var ru = CultureInfo.GetCultureInfo("ru-RU");
var orderEn = strings.OrderBy(s => s, StringComparer.Create(en, false));
Console.WriteLine("en-US: " + string.Join(" ", orderEn));
var orderRu = strings.OrderBy(s => s, StringComparer.Create(ru, false));
Console.WriteLine("ru-RU: " + string.Join(" ", orderRu));
выдаёт такой результат: en-US: Ёлочка Ель Иа Йокогама Италия
ru-RU: Ёлочка Ель Иа Италия Йокогама
Мораль этой истории: при сортировке строк всегда указывайте локаль!
Допустим есть программа которая фоном делает определенные операции, не важно какие, допустим каждые 10 секунд собирает информацию по нагрузке ЦП и RAM. Программа сама по себе десктопная, запускается ручками, надо бы сделать ее чтобы она в авторане запускалась. Вопрос: как научить ее чтобы при сворачивании она скрывалась в трей, и при необходимости опрокидывала какие либо сообщения. Например как антивирус касперского. Висит в трее, опрокидывает уведомления, когда открываешь - появляется в панеле задач
Ответ
Я использую Hardcodet.NotifyIcon.Wpf В XAML добавьте пространство имен: xmlns:tb="http://www.hardcodet.net/taskbar" В контейнер окна поместите: Для того чтобы свернуть окно в трей, подпишитесь на событие StateChanged WindowState prevState; private void Window_StateChanged(object sender, EventArgs e)
{
if (WindowState == WindowState.Minimized)
Hide();
else
prevState = WindowState;
}
Чтобы развернуть, например при левом клике по иконке в трее: private void TaskbarIcon_TrayLeftMouseDown(object sender, RoutedEventArgs e)
{
Show();
WindowState = prevState;
}
Для отображения каких-либо сообщений, можно использовать, например, Popup или ToolTip
Можно ли не используя серверную часть, а jQuery, не открывать изображение, а сразу отдать его на скачивание?
Ответ
Без использования серверной части нужное вам действие можно реализовать, используя атрибут download Скачать изображение
Подробнее про атрибут download читайте тут Поддержку браузерами можно увидеть тут
Если нужно решение именно на js/jQuery, можно копнуть в сторону DownloadJS и ему подобных готовых решений. Пример работы:
window.downloadFile = function(sUrl) {
//iOS devices do not support downloading. We have to inform user about this.
if (/(iP)/g.test(navigator.userAgent)) {
alert('Your device does not support files downloading. Please try again in desktop browser.');
return false;
}
//If in Chrome or Safari - download via virtual link click
if (window.downloadFile.isChrome || window.downloadFile.isSafari) {
//Creating new link node.
var link = document.createElement('a');
link.href = sUrl;
if (link.download !== undefined) {
//Set HTML5 download attribute. This will prevent file from opening if supported.
var fileName = sUrl.substring(sUrl.lastIndexOf('/') + 1, sUrl.length);
link.download = fileName;
}
//Dispatching click event.
if (document.createEvent) {
var e = document.createEvent('MouseEvents');
e.initEvent('click', true, true);
link.dispatchEvent(e);
return true;
}
}
// Force file download (whether supported by server).
if (sUrl.indexOf('?') === -1) {
sUrl += '?download';
}
window.open(sUrl, '_self');
return true;
}
window.downloadFile.isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
window.downloadFile.isSafari = navigator.userAgent.toLowerCase().indexOf('safari') > -1;
Скачать картинку
Еще несколько вариантов:
File downloading using client-side JavaScript
jQuery File Download
How to force download a file with JavaScript
Download Files with JavaScript
Допустим есть кусок кода: char *ptr = (char*)malloc(needed_size);
if (!ptr) {
error_handling();
} else {
do_something_without_freeing_ptr();
free(ptr);
ptr = 0;
}
Может ли вызов free не отработать/отработать неправильно и к каким последствиям это может привести?
Подразумевается, что между вызовом malloc и free выделенная память не освобождается, значение указателя не изменяется. Не лучше ли, во избежание случайного изменения значения ptr, писать: char * const ptr = malloc(needed_size);
Это не избавит от возможности написать free(ptr); free(ptr);, но по крайней мере убережет от чего-то типа ptr = NULL;
Ответ
free определена как функция, не возвращающая значений, т.е. возможности вернуть ошибку у неё нет. Если ей передать указатель полученный не от calloc, malloc, realloc, либо вызвать повторно для одного и того же указателя или изменить байты за пределами запрошенного массива, действия зависят от реализации. Обычно это приводит к непредсказуемым ошибкам в программе, возможно в совершенно другом месте. Такие ошибки трудно локализовать. К примеру, в начале выделенного куска памяти перед тем, на что указывает указатель, обычно находится заголовок — структура с информацией об этом куске и о следующем. Кроме этого, где-то может быть информация о свободных кусках. Если, например, в результате функции gets() будет испорчен заголовок для следующего блока, то проявиться эта ошибка может даже не когда этот блок будет выделен malloc, а когда этот блок будет освобождаться. Есть библиотеки реализующие набор функций calloc, malloc, realloc, free с дополнительными средствами обнаружения их ошибочного использования. Написать char * const ptr = malloc(needed_size); можно, но это не гарантирует, что вы не скопируете указатель в другую переменную или примените индекс за пределами [0; needed_size[.
иногда возникает необходимость работать из браузера (например, firefox) как-будто бы из другой точки сети (куда есть доступ по протоколу ssh).
например, нужно работать с веб-сайтом, который доступен только в локальной сети, из внешнего мира. при этом есть ssh-доступ к машине в этой локальной сети.
или при доступе к веб-сайту требуется «прикинуться» работающим из другой страны (и есть ssh-доступ к серверу в этой стране).
или в локальной сети вообще нет доступа в интернет, но есть ssh-доступ к машине, на которой соединения с интернетом разрешены.
как всё это осуществить? как настроить браузер? как запускать ssh-клиент?
Ответ
предположим, что вы подключаетесь к некоему серверу по протоколу ssh такой командой: $ ssh user@server
тогда вам потребуется:
запустить ssh-клиент с опцией -D порт, тогда программа ssh будет слушать указанный порт на локальном компьютере и (пока работает) все обращения к этому порту по протоколу socks будет ретранслировать на сервер: $ ssh -D 1122 user@server
номер порта здесь произвольный, но, конечно, должен быть больше 1024 и меньше максимального номера порта (скорее всего, в вашей системе это 65536), и, конечно, не должен использоваться каким-нибудь другим локальным процессом.
в браузере firefox на странице about:config измените следующие параметры:
network.proxy.type = 1 (0 — отключить proxy)
network.proxy.socks = 127.0.0.1
network.proxy.socks_port = 1122 (тот порт, что вы указали выше)
network.proxy.socks_remote_dns = true (dns-запросы тоже будут отправляться через туннель)
вышеперечисленные настройки можно сделать и с помощью «мышки» — на странице "preferences": "advanced" → "network" → "settings".
для отключения проксирования достаточно поменять один параметр — network.proxy.type = 0 вероятно, достаточно удобным будет завести новый профиль в firefox с этими настройками, чтобы они не мешали «обычной» работе. запустить firefox, чтобы он показал диалог выбора профилей, можно примерно так: $ firefox --no-remote -P
можно и сразу запускать нужный профиль. например, если вы назвали профиль proxy $ firefox --no-remote -P proxy
скорее всего, подобные настройки можно осуществить и в других браузерах. обратитесь к документации вашего браузера по поводу использования socks-proxy
Зачастую при любой разработке возникает необходимость написать код, про который известно заранее что он:
Крайне не гибок. Или..
Может вызвать баги, проблемы в дальнейшем. Или..
Совершенно не читаем.
Или такой код достаётся по наследству, и хочется пометить места, которые надо затем выправить. Такой код называется по-русски костыль. К сожалению на англоязычных сайтах трудно найти информацию об этом, так как у них термин "костыль" - отсутствует в принципе. Рекомендуют переводить, как "kludge" - но это не часто понимают. Вопрос - как помечать костыли в коде комментариями, чтобы было просто составить список из всех костылей в проекте, и крайне желательно - чтобы была их обозримость в IDE, может даже расстановка приоритетов? Меня больше интересует PhpStorm, но другим будет интересно узнать про их IDE. P.S.
Есть конечно спец-метка в комментах TODO, но хотелось бы представлять костыли и TODO отдельно друг от друга, всё таки они сильно разные по сути. Поэтому некоторые договариваются о специальных комментах вроде: /* TRASHCODE {why below code is bad} */
...
/* TRASHCODE end*/
Потом по коду выискать просто, но помощи IDE в обозрении костылей в таком случае нет.
Ответ
хотелось бы представлять костыли и TODO отдельно друг от друга
Во-первых, все приличные IDE кроме TODO понимают "из коробки" ещё и FIXME
но помощи IDE в обозрении костылей в таком случае нет
Во-вторых, все приличные IDE :) умеют добавлять пользовательские таск-теги. PhpStorm (и любые другие джетбрейновские):
Eclipse (можно кастомизировать даже для каждого языка/проекта):
для FIXME и TODO - можно обозначать конец? То есть выделить с помощью комментов блок.
Насколько понимаю - нет, везде отслеживается только одна строка с ключевым словом. Максимум что можно - кликнуть по ней в соответствующей закладке и перейти к этому месту в исходнике. CLion
Подключил на страницу несколько суперплагинов: $("*[data-foo]").foo();
$(".bar").bar();
$("p a b i").baz();
Но после загрузки через AJAX код перестает работать! Как это исправить?!
Ответ
Говорить, что "код перестает работать" - некорректно. Потому что код работать и не начинал. Когда вы пишите $(селектор).метод() - это означает однократный вызов метода. Этот метод применяется ко всем элементам, соответствующим переданному селектору, которые в этот момент были на странице Обычно говорят, что чтобы исправить ошибку, надо после обновления страницы через ajax выполнить код еще раз. Но это не всегда верно. Повторное выполнение вызова вида $(".bar").bar(); вызовет плагин bar не только на новых элементах - но и на старых. В лучшем случае будет бесполезно потраченное время. Но в худшем случае из-за повторного вызова что-нибудь поломается (а если вы подписывались на события - то что-нибудь поломается гарантировано!). Поэтому надо применять плагины только к обновленному контейнеру. Также бывают грабли с тем, как вызывать эти плагины после обновления. Обычно это пытаются делать через инлайн script в ответе сервера - но в таком случае этот скрипт не имеет доступа к обновляемому элементу. Надо искать в коде где происходит само обновление - и править там.
Выше был общий принцип. Ниже я напишу способ, которым можно попытаться заставить заработать код в простом случае.
Собираем все "улучшения" страницы в одном месте: applyPlugins(); // ...
function applyPlugins() {
$("*[data-foo]").foo();
$(".bar").bar();
$("p a b i").baz();
}
Изменяем получившуюся функцию так, чтобы она действовала только внутри переданного ей контейнера: applyPlugins($(document)); function applyPlugins($cnt) {
$cnt.find("*[data-foo]").foo();
$cnt.find(".bar").bar();
$cnt.find("p a b i").baz();
}
Здесь мы воспользовались методом find, который ищет дочерние элементы. Важно! Функция applyPlugins не должна обращаться к элементам за пределами переданного ей контейнера $cnt!
Находим в коде те места, где выполняется динамическое обновление содержимого или создание элементов. Это может быть вызов .html(...) $.ajax({
// ... success: function (data) {
$("#some_block").html(data);
}
});
В таком случае надо после вызова html добавить вызов applyPlugins $.ajax({
// ... success: function (data) {
applyPlugins($("#some_block").html(data));
}
});
Это может быть вызов .load() $("#some_block").load("http://some/url");
В таком случае надо добавить туда параметр с функцией обратного вызова: $("#some_block").load("http://some/url", function () {
applyPlugins($(this));
});
Это может быть и что-то другое. Но все же надеюсь что вы это место найдете - это же ваш код, а не чей-то еще :)
Способ выше не будет работать если используемый для плагина селектор проходит через динамический контейнер: $(".foo .bar .baz").somePlugin(); $(".bar").load(...);
В таком случае попытка прямого переписывания в applyPlugins в виде $cnt.find(".foo .bar .baz").somePlugin() будет неудачной, поскольку ни .foo, ни .bar не являются дочерними элементами для обновляемого контейнера. В таком случае вам, наверное, стоит более внимательно отнестись к тому что и как вы обновляете или загружаете вместо слепого применения трюка с applyPlugins. Или же можно попытаться сделать как-то так, чтобы предусмотреть все случаи - но этот код для понимания и для отладки будет довольно тяжелым: $cnt.find(".foo .bar .baz").somePlugin();
$cnt.filter(".foo, .foo *").find(".bar .baz").somePlugin();
$cnt.filter(".foo .bar, .foo .bar *").find(".baz").somePlugin();
(Здесь проверяется, является ли текущий контейнер элементом .foo или его дочерним элементом, и если является - в пути .foo .bar .baz пропускается первый элемент. Этот код предполагает, что один .foo не может быть вложен в другой. То же самое для .bar.)
PS хотя я говорил только про плагины, ответ можно применять и для подписки на события. Но это будет не самый лучший способ - потому что есть способ проще. Большинство событий является всплывающими - а потому их можно отлавливать в корне документа. И JQuery имеет встроенные механизмы для фильтрации всплывших событий. Пример: $(document).on("click", "a[data-href]", function (e) {
// ...
})
Этот обработчик будет слушать нажатия на любые ссылки с установленным атрибутом data-href независимо от того, как и когда они появились на странице.
#include
using namespace std;
int main()
{
int b[10];
int ( *a )[ 10 ]; // эта
a = b; // error
a[ 0 ] = new int; // error
a = new int; // error }
Пытаюсь методом подбора понять что это и как это используется
Ответ
Чтобы проще было понять запись int ( *a )[ 10 ];
можно ввести определение алиаса для массива typedef int T[10]; T *a;
то есть объекты, которые может адресовать указатель, представляют собой целочисленные массивы из десяти элементов. Если вы хотите, например, чтобы этот указатель адресовал такой массив, вы можете написать typedef int T[10]; T b; T *a;
a = &b;
Тогда выражение *a или a[0] представляет собой массив b Например, вы можете написать typedef int T[10]; T b; T *a;
a = &b; for ( int i = 0; i < 10; i++ ) a[0][i] = i;
Если хотите динамически выделить массив, то вам следует записать typedef int T[10]; T *a;
a = new T[1];
Это эквивалентно следующему фрагменту кода int ( *a )[10]; a = new int[1][10];
То есть такой указатель используется обычно при работе с двумерными массивами. Например, #include int main()
{
const size_t M = 2;
const size_t N = 10; int b[M][N] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }
}; for ( int ( *a )[N] = b; a != b + M; ++a )
{
for ( int x : *a ) std::cout << x << ' ';
std::cout << std::endl;
}
}
Вывод на консоль 0 1 2 3 4 5 6 7 8 9
9 8 7 6 5 4 3 2 1 0
Есть сервер с несколькими БД. Хочется перенести неиспользуемые на другой сервер, как понять используются ли БД и когда была обработка запросов последний раз?
Ответ
Предлагаю рассмотреть следующие варианты: Для понимания использования БД можно воспользоваться:
Использование индексов в БД
Когда последний раз модифицировались объекты БД
Сколько было транзакций по конкретной БД с момента запуска
Для анализа активности БД:
Проанализировать планы запросов по конкретной БД
Проанализировать активность файлов БД за определённый промежуток времени
Приступим! Поиск использования индексов в БД SQL Server хранит статистику по обращениям к индексам на чтение и запись, в частности из представления SYS.DM_DB_INDEX_USAGE_STATS мы можем получить время последнего обращения (LAST_USER_SEEK,LAST_USER_SCAN,LAST_USER_LOOKUP) и обновления (LAST_USER_UPDATE) индекса. Перейдите в нужную БД и выполните: SELECT
T.NAME
,USER_SEEKS
,USER_SCANS
,USER_LOOKUPS
,USER_UPDATES
,LAST_USER_SEEK
,LAST_USER_SCAN
,LAST_USER_LOOKUP
,LAST_USER_UPDATE
,modify_date
FROM
SYS.DM_DB_INDEX_USAGE_STATS I JOIN
SYS.TABLES T ON (T.OBJECT_ID = I.OBJECT_ID)
WHERE DATABASE_ID = DB_ID()
ORDER BY LAST_USER_UPDATE DESC
GO
Дата модификаций объектов Чтобы получить дату модификации объектов в БД, необходимо перейти в нужную БД, выполнить и обратиться внимание на поле modify_date: SELECT * FROM sys.objects ORDER BY modify_date DESC
Анализ активности по количеству выполненных транзакциях в БД Представление sys.dm_os_performance_counters позволяем посмотреть всевозможные счётчики производительности SQL Server (сбрасывается после рестарта), один из них поможет с нашим вопросом, это счётчик Transactions/sec. Выполните следующий скрипт и вы получите информацию по всем БД: SELECT *
FROM sys.dm_os_performance_counters
WHERE counter_name like 'Transactions/sec%'
GO
Поиск планов запросов по конретной БД Мы можем, использую ряд представлений, понять какие планы с какими БД работают. Это очень удобно, так как это позволит понять какие запросы выполняются с нашими БД (информация сбрасывается после рестарта и при вытеснении планов из кэша). Обязательно укажите название вашей БД тут WHERE pl.query_plan LIKE '%MyDb%'. Обратите внимание, что разбор планов запросов это сложная операция, поэтому запрос может выполняться долго, не выполняйте следующий запрос если ваш сервер испытывает трудности: SELECT SUBSTRING(tx.[text],
(qs.statement_start_offset / 2) + 1,
(CASE WHEN qs.statement_end_offset =-1 THEN DATALENGTH(tx.text) ELSE qs.statement_end_offset END - qs.statement_start_offset)
/ 2 + 1) AS QueryText,
case when pl.query_plan LIKE '%%' then 1 else 0 end as [Missing Indexes?],
qs.execution_count,
qs.total_worker_time/execution_count AS avg_cpu_time,
qs.total_worker_time AS total_cpu_time,
qs.total_logical_reads/execution_count AS avg_logical_reads,
qs.total_logical_reads,
qs.creation_time AS [plan creation time],
qs.last_execution_time [last execution time],
CAST(pl.query_plan AS XML) AS sqlplan
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) AS pl
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS tx
WHERE pl.query_plan LIKE '%MyDb%'
ORDER BY execution_count DESC OPTION (RECOMPILE);
GO
Анализ активности файлов БД за промежуток времени Кроме всего прочего мы можем отследить активность файлов БД за определённый промежуток времени. По-умолчанию скрипт настроен на сбор информации с момента запуска на 1 минуту, чтобы это изменить следует поправить вот тут WAITFOR DELAY '00:01:00'; . Информация собирается для всех БД: IF EXISTS (SELECT * FROM [tempdb].[sys].[objects]
WHERE [name] = N'##SQLskillsStats1')
DROP TABLE [##SQLskillsStats1]; IF EXISTS (SELECT * FROM [tempdb].[sys].[objects]
WHERE [name] = N'##SQLskillsStats2')
DROP TABLE [##SQLskillsStats2];
GO SELECT [database_id], [file_id], [num_of_reads], [io_stall_read_ms],
[num_of_writes], [io_stall_write_ms], [io_stall],
[num_of_bytes_read], [num_of_bytes_written], [file_handle]
INTO ##SQLskillsStats1
FROM sys.dm_io_virtual_file_stats (NULL, NULL);
GO WAITFOR DELAY '00:01:00';
GO SELECT [database_id], [file_id], [num_of_reads], [io_stall_read_ms],
[num_of_writes], [io_stall_write_ms], [io_stall],
[num_of_bytes_read], [num_of_bytes_written], [file_handle]
INTO ##SQLskillsStats2
FROM sys.dm_io_virtual_file_stats (NULL, NULL);
GO WITH [DiffLatencies] AS
(SELECT
[ts2].[database_id],
[ts2].[file_id],
[ts2].[num_of_reads],
[ts2].[io_stall_read_ms],
[ts2].[num_of_writes],
[ts2].[io_stall_write_ms],
[ts2].[io_stall],
[ts2].[num_of_bytes_read],
[ts2].[num_of_bytes_written]
FROM [##SQLskillsStats2] AS [ts2]
LEFT OUTER JOIN [##SQLskillsStats1] AS [ts1]
ON [ts2].[file_handle] = [ts1].[file_handle]
WHERE [ts1].[file_handle] IS NULL
UNION
SELECT
[ts2].[database_id],
[ts2].[file_id],
[ts2].[num_of_reads] - [ts1].[num_of_reads] AS [num_of_reads],
[ts2].[io_stall_read_ms] - [ts1].[io_stall_read_ms] AS [io_stall_read_ms],
[ts2].[num_of_writes] - [ts1].[num_of_writes] AS [num_of_writes],
[ts2].[io_stall_write_ms] - [ts1].[io_stall_write_ms] AS [io_stall_write_ms],
[ts2].[io_stall] - [ts1].[io_stall] AS [io_stall],
[ts2].[num_of_bytes_read] - [ts1].[num_of_bytes_read] AS [num_of_bytes_read],
[ts2].[num_of_bytes_written] - [ts1].[num_of_bytes_written] AS [num_of_bytes_written]
FROM [##SQLskillsStats2] AS [ts2]
LEFT OUTER JOIN [##SQLskillsStats1] AS [ts1]
ON [ts2].[file_handle] = [ts1].[file_handle]
WHERE [ts1].[file_handle] IS NOT NULL)
SELECT
DB_NAME ([vfs].[database_id]) AS [DB],
LEFT ([mf].[physical_name], 2) AS [Drive],
[mf].[type_desc],
[num_of_reads] AS [Reads],
[num_of_writes] AS [Writes],
[ReadLatency(ms)] =
CASE WHEN [num_of_reads] = 0
THEN 0 ELSE ([io_stall_read_ms] / [num_of_reads]) END,
[WriteLatency(ms)] =
CASE WHEN [num_of_writes] = 0
THEN 0 ELSE ([io_stall_write_ms] / [num_of_writes]) END,
[AvgBPerRead] =
CASE WHEN [num_of_reads] = 0
THEN 0 ELSE ([num_of_bytes_read] / [num_of_reads]) END,
[AvgBPerWrite] =
CASE WHEN [num_of_writes] = 0
THEN 0 ELSE ([num_of_bytes_written] / [num_of_writes]) END,
[mf].[physical_name]
FROM [DiffLatencies] AS [vfs]
JOIN sys.master_files AS [mf]
ON [vfs].[database_id] = [mf].[database_id]
AND [vfs].[file_id] = [mf].[file_id]
ORDER BY [WriteLatency(ms)] DESC;
GO IF EXISTS (SELECT * FROM [tempdb].[sys].[objects]
WHERE [name] = N'##SQLskillsStats1')
DROP TABLE [##SQLskillsStats1]; IF EXISTS (SELECT * FROM [tempdb].[sys].[objects]
WHERE [name] = N'##SQLskillsStats2')
DROP TABLE [##SQLskillsStats2];
GO
P.S. Есть, конечно, простой и 100% способ - отключить БД и ждать пока зазвонит телефон)