Хочу установить Linux Mint на флешку. Именно установить, а не записать образ. При записи iso-образа получается, что программы, устанавливаемые при загрузке с флешки, забываются при перезагрузке. Всякие настройки - тоже. Хочу получить полноценную систему, но на флешке. Как этого добиться?
Ответ
полноценную систему
запустите установку и выберите «флэшку» в качестве целевого диска. на неё же и загрузчик поставьте на соответствующей стадии установки
Почему при таком построение цикла for, получается бесконечные вывод нулей? int i;
for (i = 0; i < 10; i = i++) {
System.out.println(i);
}
Ответ
Ваше выражение: i = i++. Что здесь происходит по шагам:
Сначала i = 0
Вычисляется значение после знака равно. Это ноль: result = i = 0
Вычисляется постфиксный инкремент. Теперь i = i+1 = 1
Результат выражения записывается в i. В итоге: i = result = 0
Можно заменить на: i = ++i. Тогда:
Сначала i = 0
Вычисляется префиксный инкремент. Теперь i = i+1 = 1
Вычисляется значение после знака равно: result = i = 1
Результат выражения записывается в i. В итоге: i = result = 1
В общем, постфиксный инкремент в операторе присваивания над той же переменной ничего полезного не делает. Отсюда и Ваш бесконечный цикл.
Для чего нужно использовать файл .gitignore, если можно просто выбрать файлы которые необходимо закоммитить, и сделать это?
Ответ
Есть несколько задач, которые наиболее эффективно решаются с использованием файла .gitignore
Не мучаться с выбором нужных файлов для индексации (которая git add). В большом проекте часто бывает много файлов, которые не подлежат версионированию. Свою лепту вносят редакторы и среды разработки, компиляторы, дебаггеры, прочие инструменты и сама операционная система. А ещё вам может быть удобно хранить какие-то промежуточные результаты в папке tmp Настройка .gitignore позволяет не выискивать нужные файлы, а добавлять всё сразу или по крайней мере уточнять меньше. Соглашусь с комментарием Etki, подход "просто выбрать нужные" совершенно не масштабируется.
Сделать локальный конфиг, который не будет затронут pull-ом Предположим, для работы вашего проекта нужен конфиг. Значения в нем зависимы от места выполнения, погоды и настроения разработчика. Вариант 1: сделать local.conf и вносить изменения при необходимости. Если вы его вдруг добавите и закоммитите, то у вас будут конфликты при pull/push. Или с пуллом к вам придёт чужой конфиг. Вариант 2: версионируемый local.conf.example и игнорируемый local.conf. В работе используется второй, для его формирования вручную или автоматически используется первый. Хорошо, удобно и не препятствует автоматизации. У меня так конфигурируются автотесты, запускаемые локально и на сервере интеграции.
Защитить чувствительную информацию от случайного раскрытия Случается, что вы случайно добавили и закоммитили ключи или пароли от какого-нибудь облачного хранилища, например Amazon. А потом запушили это добро на GitHub. Что нужно делать в такой ситуации? Очень быстро бежать и менять все ключи и пароли, т.к. почти наверняка за ваш счёт уже майнятся биткойны. Если так уж необходимо хранить чувствительную информацию в папке проекта, то нужно положить её в под-папку, игнорируемую git.
Быстро очищать проект от временных файлов Предположим, что вы пишете на компилируемом языке и при построении вашего проекта формируется множество промежуточных файлов (объектные, прекомпиляция, вот это всё). Перед каждой сборкой необходимо их удалять, чтобы в случае чего не прилинковать лишнее. Можно делать это вручную. Можно написать скрипт. А можно просто добавить их в .gitignore и делать так: git clean -fX
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
Вот кусок кода. Метод setFlags на вход получает int, но никак не boolean. Что значить оператор ИЛИ между двумя константами при передаче в метод?
Ответ
| - это побитовое ИЛИ над целочисленными операндами и логическое ИЛИ над булевыми операциями.
|| - это логическое ИЛИ над булевыми операндами (при этом правый операнд будет вычислен, только если левый вычислялся как false). Побитовое ИЛИ часто используют при работе с флагами, упакованными в целочисленное значение. Каждому флагу соответствует число вида 2^n. В двоичном представлении это будет одна единица с n нолей слева: 0x01 == 0b00000001
0x02 == 0b00000010
0x04 == 0b00000100
0x08 == 0b00001000
...
0x80 == 0b10000000
Для получения битовой маски, соответствующей объединению (включению) нескольких флагов, их складывают при помощи побитового ИЛИ. 0b00000001 | 0b00001000 == 0b00001001
Для проверки, включен ли конкретный флаг, используют побитовое И. Если результат ненулевой - флаг включен: ((0b00001001 & 0b00001000) != 0) // true, флаг включен
((0b00001001 & 0b01000000) != 0) // false, флаг выключен
Пытаюсь разбираться с наследованием в Java. Есть некоторый код: class A {
A getThis() {
System.out.println("call getThis() from A");
return this; //(3)
} //(3) Object getSuper() {
System.out.println("call getSuper() from A");
return null;}
} class B extends A {
B getThis() {
System.out.println("call getThis() from B");
return this;
} A getSuper() {
System.out.println("call getSuper() from B");
return super.getThis();
}
} class Tester {
public static void main (String[] args) {
Object a = new B().getSuper(); //(1)
System.out.println(a);
a = new B().getSuper().getSuper(); //(2)
System.out.println(a);
}
}
В результате на консоль выводится следующий текст:
call getSuper() from B
call getThis() from A
B@25154f
call getSuper() from B
call getThis() from A
call getSuper() from B
call getThis() from A
B@10dea4e
Я ожидал, что при отработке строки (1) в a будет лежать экземпляр класса A, а после отработки строки (2) в a будет лежать null. Почему в результате возврата this из строки (3) возвращается ссылка не на родительский класс, а на исходный?
Как я понимаю, при создании экземпляра класса B, в нём хранится ссылка на экземпляр родительского класса A. Я вижу косвенное подтверждение своих слов: При вызове конструктора класса B происходит вызов конструктора класса A.
Даже при переопределении метода f в классе B можно добраться до метода f класса A через конструкцию super.f()
Несмотря на это, при работе с экземпляром класса B, я не вижу способа вернуть из него ссылку на экземпляр класса A, который используется в нём. Есть ли какой-то способ всё же реализовать такую возможность?
Ответ
Мне кажется вы путаете понятия Класс и объект. Класс – это способ описания сущности, определяющий состояние и поведение, зависящее от этого состояния, а также правила для взаимодействия с данной сущностью (контракт). Объект (экземпляр) – это отдельный представитель класса, имеющий конкретное состояние и поведение, полностью определяемое классом. Ключевое слово this указывает не на класс, а на экземпляр класса (объект). Ключевое слово super обеспечивает доступ к свойствам и методам этого же объекта но описанным в суперклассе. Например: Вы создали объект бирюса класса Холодильник, а класс Холодильник наследуется от класса БытоваяТехника. Объект бирюса является и холодильником, и бытовой техникой. this вернет ссылку на объект бирюса, не важно через какой класс получена ссылка Холодильник или БытоваяТехника, объект от этого не меняется. Так и у вас объект a является экземпляром класса B, одновременно является экземпляром класса А, так как от него наследуется. Когда Вы вызываете метод getSuper() по цепочке в итоге возвращается this, то есть ссылка на объект a Определения класса и объекта взяты отсюда
На сайте есть header, content и footer блоки.
У content на разных страницах разная высота, бывает что высота меньше чем body и тогда шапка находится не внизу страницы а выше. Как правильно позиционировать футер? Нужно ли устанавливать минимальную высоту для content чтобы прижать footer к низу? Хотя минимальную высоту я установить не могу, так как высота на разных устройствах разная. Как поступать в таких случаях?
Ответ
футер прижимается вниз путём его абсолютного позиционирования и вытягивания высоты родительских блоков: html, body и блока с классом .wrapper на 100%. При этом конкретному блоку .content необходимо задать нижний отступ, который равен или больше высоты футера, в противном случае последний закроет часть содержимого. * {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
}
.wrapper {
position: relative;
min-height: 100%;
}
.content {
padding-bottom: 90px;
}
.footer {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 80px;
} Разметка
Создаю спрайт с помощью gulp (плагин gulp-svg-sprites). В Mozilla отображается нормально, в хроме открываю - всё сдвинуто.
Если из конечного svg я генерирую png-спрайт (плагин gulp-svg2png), и подключаю его вместо svg, то во всех браузерах отображается нормально. т.е. я так понимаю это что-то связано именно из интерпретацией браузером. Как исправить? Пример моего спрайта после галпа есть здесь . При изменении размеров бегунком в хроме этот баг тоже можно увидеть (хорошо заметно при максимальном увеличении, на белых - когда инвертировать фон). В мозиле всё нормально. P.S. Обновил спрайт - установил, чтобы viewBox у всех элементов начинался с "0 0. не помогло. Настройки gulp: gulp.task('svg-sprites:build', function () {
return gulp.src(options.theme.img_svg_src + '*.svg')
.pipe(svgSprite())
.pipe(gulp.dest(options.theme.img_src + 'dict'))
.pipe(filter(options.theme.img_src + 'dict/svg/*.svg'))
.pipe(gulp.dest(options.theme.img_src + 'dict'));
});
Ответ
Короткий ответ Удалите атрибут viewBox="0 0 41 2023" из SVG. Впрочем, остальные viewBox тоже можете удалить. Можно сделать это автоматически с помощью svgo (плагин removeViewBox). Длинный ответ Это похоже на баг Chrome, связанный с расчетом background-size, когда background-size по горизонтали не кратен ширине viewBox в SVG. Смотрите, у вас background-size задается в em: 4.1em 202.3em (sprite.css:5). А изменение размеров картинок задается через font-size от 2 до 14 px. Исходное значение font-size равно 10px, поэтому при открытии страницы размер фона в пикселях получается 41x2023 px, как раз как viewBox в SVG. Можно прописать background-size: 41px 2023px и все останется по-прежнему. Но если указать на пиксель меньше: background-size: 40px 2023px, мы увидим смещение по вертикали. Хотя, казалось бы, картинка должна стать просто немного уже. Поэтому при изменении шрифта все едет. Если задать размер шрифта 11px, то ширина фона получится 4.1em * 11px = 45.1px, а это не кратно 41 (ширина исходного viewBox). Следующее значение шрифта, при котором все показывается нормально - 20px: размер background-size по горизонтали становится 82px, что кратно 41. Я точно не берусь описать все особенности этого бага (иногда он проявляется, иногда нет), но суть в том, что решение простое: удалите атрибут viewBox="0 0 41 2023" из SVG. Впрочем, остальные viewBox тоже можете удалить. Можно сделать это автоматически с помощью svgo (плагин removeViewBox). Пример для gulp gulp.task('remove-viewbox', function() {
var svgmin = require('gulp-svgmin'); return gulp.src('src/*.svg')
.pipe(svgmin({
plugins: [ {removeViewBox: true} ]
}))
.pipe(gulp.dest('dest/'));
});
Мне нужно на сайте обновлять google banner каждых например 3-5 минут. Без рефреша всей страницы и так, чтобы гугл не забанил. Возможно ли такое? Пример, кода банера.
Ответ
Да, можно, пример отсюда Создаете файл refresh-banner-iframe.php где будет ваш скрипт для AdSense:
Добавляете iframe с сылкой на этот файл:
Для обновления баннера вызываете через javascript: $url = $('iframe').attr("src");
$('iframe').attr("src","about:blank");
$('iframe').attr("src",$url);
Насчет забанит Google вас или нет не знаю.
Пишу программу в С#, которая предполагает простое анкетирование пользователей с последующем выводом данных. Как правильно организовать в консольном приложении C# получение от пользователя данных о дате его рождения?
Ответ
Сделайте метод, который в цикле опрашивает ввод, пока не будет введено правильное значение: DateTime inputDoB()
{
DateTime dob; // date of birth
string input; do
{
Console.WriteLine("Введите дату рождения в формате дд.ММ.гггг (день.месяц.год):");
input = Console.ReadLine();
}
while (!DateTime.TryParseExact(input, "dd.MM.yyyy", null, DateTimeStyles.None, out dob)); return dob;
}
Использование: var dob = inputDoB();
Можно задать произвольный формат вводимой даты. Например, "d.M.yyyy", что позволит вводить дату в виде 1.4.2017
В чем заключается разница между ListView и RecyclerView?
Ответ
RecyclerView был создан в качестве улучшения ListView, так что да, вы можете создать прилагаемый список с контролем ListView, но с использованием RecyclerView проще в нем:
Повторное использование клеток при прокрутке вверх / вниз - это возможно при реализации View Holder адаптера ListView, но это необязательная вещь, в то время как в RecycleView это путь по умолчанию записи адаптера.
Разъединяет список из контейнера - так что вы можете поместить элементы списка легко во время выполнения в различных контейнерах (LinearLayout, GridLayout) с установкой LayoutManager .
Анимирует общие действия списка - Анимации развязаны и делегированы ItemAnimator .
Существует больше о RecyclerView, но я думаю, что эти точки являются основными.
Таким образом, в заключение, RecyclerView является более гибким управлением для обработки «список данных», который следует модели делегирования проблем и оставляет за собой только одну задачу - переработка предметов.
Я начал изучения библиотеки STL и нашел такой интересный контейнер, как deque, но я не понял, в чем его преимущество, если можно заменить его другими контейнерами из того же STL?
Ответ
А чем вообще один контейнер отличается от другого? И вообще, все их можно заменить обычным массивом... В конце концов, какая разница, искать ли элемент в контейнере час или пару секунд, или - ну что тут такого страшного, если вставка в начало массива требует перемещения всех его элементов? Или это существенно? Тогда учтите, что дек обеспечивает быструю вставку-удаление с обоих концов контейнера - чего, например, не может обеспечить vector, но при этом быстрое (хотя чуть медленнее, чем у vector) обращение к любому элементу внутри, чего, например, не может обеспечить list. Но при этом он не может обеспечить быстрый поиск, как у set или unordered_set... Ну, а чтобы вам было легче выбирать, какой именно контейнер вам нужен - вот неплохая шпаргалка:
Еще одна сводная шпаргалка по функциям контейнеров:
Я пишу css-правило .nav-users {
color: red;
}
но на странице нечего не меняется: цвет остаётся серым.
Ответ
Браузеры предоставляют отличные инструменты для отладки css. Не надо ждать, пока кто-то угадает, в чём проблема. Надо просто взять и посмотреть, что же происходит. Покажу на примере Хрома. Сначала надо обновить страницу со сбросом кэша.
В большинстве браузеров это Ctrl + F5 Если не помогло, то по исследуем по следующему плану:
Щёлкнуть проблемный элемент правой кнопкой и выбрать пункт Исследовать элемент
Появится панель отладки, на которой на вкладке Elements выделен кликнутый элемент. Если нужен другой, можно перейти к нему. Затем следует обратить внимание на вкладки Styles и Computed
Если в element.style есть интересующее свойство, то
если в html-разметке прописан стиль в атрибуте style, удаляем оттуда лишнее
если нет, кончаем читать этот ответ и переходим к отладке скриптов, которые этот стиль выставляют (либо перебиваем !importantом, что делать крайне не рекомендуется)
На вкладке Styles надо найти свой селектор.
Если его там нет, то проблема в опечатке или подключении css-файла.
Как видим, свойство зачёркнуто, но восклицательного знака (говорящего о неверном значении) нет. Это означает, что есть другое правило, имеющее больший приоритет. В простых случаях достаточно посмотреть на вышестоящие правила и понять, что там надо. В более запутанных стоит заглянуть на вкладку Computed и посмотреть, какие вообще значения влияют:
Здесь видно, что селектор .so-header .navigation .-link перебивает наше правило.
Кликом по стрелочке можно перейти к самому правилу, но нам это сейчас не нужно.
Теперь мы знаем, что приоритет используемого правила 0 id, 3 класса, 0 тегов
Если мы уверены, что наше правило идёт после переопределяемого, то нам достаточно той же силы. Если нет, то надо побольше. Самый простой способ - это сделать так: .nav-users.nav-users.nav-users.nav-users {
color: red;
}
Но руководствуясь здравым смыслом, стоит всё-таки сделать так: .so-header .navigation .nav-users {
color: red;
}
или так: .so-header .navigation .-link.nav-users {
color: red;
}
Должно заработать:
Если всё равно не работает. На шаге 6 стоило заглянуть в переопределяющий стиль - возможно, в нём есть !important
В таком случаем нам тоже придётся его использовать: .so-header .navigation .-link.nav-users {
color: red !important;
}
В некоторых отрывках кода наблюдаю приведение malloc() к (char *), (int *) и т.п. Зачем это делается? Например: char *p;
p = (char *)malloc(100*sizeof(char));
Ответ
Во времена динозавров в языке С не было типа void *. Идея универсального указателя void * пришла в С намного позже (причем не откуда-нибудь, а из С++). А до того времени в качестве "универсального" указательного типа использовался именно char *. Функция malloc возвращала результат именно типа char *. Именно в те времена и существовала необходимость для выполнения неявного приведения результата malloc от char * к конкретному типу указателя-получателя. В примерах кода, написанных на достандартном С, включая первые версии K&R, это приведение везде присутствует именно по этой причине. С появлением в языке типа void *, неявно приводящегося к любому указательному типу, и с последующим переходом malloc на void *, необходимость в явном приведении отпала. Однако в большом количестве старого кода его еще можно увидеть. Это приведение перекочевало и во второе издание K&R С, написанное еще до появления первого стандарта С. Несмотря на то, что второе издание задним числом привели в соответствие со стандартом С89/90, примеры кода в нем никто исправлять не стал. В результате студенты, использующие книгу K&R для обучения, "нахватываются" этот странной привычки оттуда, слепо следуя ей как "карго культу". В современном С-коде выполнять такое приведение имеет смысл разве что только в кросс-компилируемом С-С++ коде, т.к. в С++ указатель void * к другим типам сам по себе не приводится. В частности, например, при реализации кросс-компилируемых макросов и inline-функций в заголовочных файлах. (Наследием тех времен, когда в качестве универсального указателя в С использовался тип char * в современной спецификации языка является гарантия того, что объектное представление и требования выравнивания типов void * и char * обязаны совпадать.)
Справедливости ради надо заметить, что один аргумент современных любителей явно приводить результат malloc в С коде (не предназначенном для кросс-компиляции) таки содержит определенное рациональное зерно. В коде вроде T* p;
...
p = (T *) malloc(N * sizeof(T));
если кто-то поменяет тип указателя в объявлении p с T * на U *, но при этом забудет исправить выделение памяти через malloc, то в вызове malloc компилятором будет сгенерировано диагностическое сообщение о несоответствии типов указателей. Да, это действительно так. Однако более грамотным вариантом защиты от подобных проблем будет использование идиомы с "типонезависимым" выделением памяти p = malloc(N * sizeof *p);
которое само по себе "автоматически" подстроится под вышеупомянутое изменение типа.
Вопрос, собственно выбора. Чем Git лучше или хуже SVN? Почему чаще от разработчиков я слышу именно про Git и его удобства, чем про SVN, хотя как по мне, все что слышал можно делать и в SVN. Причём для обоих вариантов есть удобный Tortoise, что сводит общение с репозиториями практически на один уровень. Может просто что-то плохо рекламируют, а разницы вообще нет?
Ответ
GIT распределяется, а SVN - нет. Другими словами, если есть несколько разработчиков работающих с репозиторием у каждого на локальной машине будет ПОЛНАЯ копия этого репозитория. Разумеется есть и где-то и центральная машина, с которой можно клонировать репозиторий. Это напоминает SVN. Основной плюс в том, что если вдруг у вас нет доступа к интернету, сохраняется возможность работать с репозиторием. Потом только один раз сделать синхронизацию и все остальные разработчики получат поолную историю.
GIT сохраняет метаданные изменений, а SVN целые файлы. Это экономит место и время.
Система создания branches, versions и прочее в GIT и SVN отличаются значительно. В GIT проще переключатся с ветки на ветку, делать merge между ними. В общем GIT я нахожу немного проще и удобнее, но бывают конечно иногда сложности. Но где их не бывает?
Разумеется есть гораздо больше отличий, но я перечислил те, которые чаще всего встречаются при работе с репозиториями и на МОЙ взгляд наиболее важные.
Есть список, состоящий из объектов. Все эти объекты отличаются значением одного поля. Задача состоит в том, чтобы вывести количество объектов для каждого значения этого поля.
Ответ
Пусть список называется list, а поле по которому считаем называется Name, тогда var result = list.GroupBy(n => n.Name).Select(m => new {m.Key, Count = m.Count()});
Это у нас будет LINQ вариант, на тот случай если не захотите создавать свой "велосипед", а воспользуетесь штатными средствами языка. В противном случае @rdorn дал отличный ответ.
Как при создании объекта класса вызвать функцию, которую в дальнейшем нельзя будет вызывать (ни с помощью данного экземпляра, ни других экземпляров этого класса)?
Ответ
Для этого в C++ есть специальная функция и флаг, делается это так: std::once_flag flag;
//...
class Class
{
Class()
{
std::call_once(flag, [this]{ SomeMethod(); });
} void SomeMethod()
{...}
}
Таким образом мы вызовем SomeMethod() в конструкторе однажды, но это не запретит вызывать этот метод в других местах программы, поэтому его можно сделать приватным, но это не запретит вызов приватного метода в других методах класса. Для того, чтобы полностью исключить повторный вызов какого-либо кода, нужно весь этот код поместить в лямбду, которая передаётся в std::call_once std::once_flag flag;
//...
class Class
{
Class()
{
std::call_once(flag, [this]
{
// Тут будет код, который нужно вызывать лишь единожды
});
}
}
Как написать простой, понятный, легко обслуживаемый код, который запускает последовательно несколько асинхронных функций в javascript/jQuery?
(когда отработает одна, должна запускаться другая) Следующий пример иллюстриует мой вопрос: function f1(){ setTimeout( function(){ console.log(1); }, 30); }
function f2(){ setTimeout( function(){ console.log(2); }, 20); }
function f3(){ setTimeout( function(){ console.log(3); }, 10); }
f1(); f2(); f3();
на выходе 3 2 1
как сделать что-бы выдавало 1 2 3 ? Желательно без коллбеков - т.к. если надо запустить последовательно больше двух функций это уже тяжело читать.
Многое говорит о том что возможно решение с помощью обьекта $.Deferred, но пока не видел разумного варианта. Подобный вопрос задавался не раз, но я почему-то не нашел ответа который бы меня устроил.
Ответ
Если вы хотите использовать Обещания (Promise), то для начала вам нужно модифицировать ваши функции так, чтобы они возвращали Обещания. Например, первая из ваших функций будет иметь вид: function f1() {
return new Promise(function(resolve){
setTimeout(function() {
console.log(1);
resolve();
}, 30);
});
}
Остальные функции преобразуются аналогичным образом. Теперь у вас есть три функции (f1, f2, f3), которые возвращают Обещания и вы хотите выполнить их последовательно. Если вы не используете библиотек, вроде Bluebird, то вам придется реализовать очередь вызова Обещаний вручную. Это не так сложно, как кажется: // Аргумент "deeds" - это массив функций, которые должны выполняться
// последовательно. При этом, каждая функция должна возвращать
// Обещание (Promise).
var seqRunner = function(deeds) {
return deeds.reduce(function(p, deed) {
return p.then(function() {
// Выполняем следующую функцию только после того, как отработала
// предыдущая.
return deed();
});
}, Promise.resolve()); // Инициализируем очередь выполнения.
}
А пользоваться этой очередью нужно вот так: seqRunner([f1, f2, f3]).then(function() {
console.log('Done!');
});
А вот и JSFiddle с рабочим примером
Замечание: Если у вас заранее известное, небольшое число функций, то можно вообще обойтись без функции seqRunner и связывать функции вручную: f1().then(function() {
return f2();
}).then(function() {
return f3();
}).then(function() {
console.log('Done!');
});
PageFragment fragment = new PageFragment();
Bundle args=new Bundle();
args.putInt("num", page);
fragment.setArguments(args);
return fragment;
Вопрос: Зачем Bundle нужен? чтобы создать связку ключ-значение? или у него есть еще функции?
Ответ
Bundle необходим для временного хранения данных в процессе выполнения. Это отличный выбор при передаче данных между активностями. Это способ для сохранения данных при смене ориентации экрана. Вообщем это сохранённые данные, которые система для использует для восстановления предыдущего состояния. Представляет собой набор пар ключ-значение.
Всем привет! Я новичок и я пытаюсь создать вот такую вот тень для фотографий: А получается, к сожалению вот так и самостоятельно решить эту проблему у меня не получается:
Т.е. тень верхней фотографии падает на нижнюю, а этого не должно быть. К каждой фотографии применяю display:block; position:absolute; и z-index:число;
Ответ
Как вариант решения данной проблемы, могу посоветовать следующий код (в данном случае вам необходимо тень делать у контейнера, содержащего элементы):
.container {
filter: url(drop-shadow.svg#drop-shadow);
filter: drop-shadow(2px 2px 10px rgba(0, 0, 0, .5));
}
.element {
position: relative;
width: 150px;
height: 150px;
}
.element__one {
background-color: lightgreen;
}
.element__two {
top: -70px;
left: 40px;
background-color: lightblue;
}
.element__three {
top: -140px;
left: 80px;
background-color: pink;
}
Подробнее про идею для решения данной проблемы можно почитать в книге Леа Веру: Секреты CSS в главе 16 "Падающие тени неправильной формы". Если коротко, то в данном решении используются фильтр SVG, и упрощенный аналог на CSS, и если не поддерживается одно свойство, то будет применено другое. Про фильтры подробнее можно прочитать тут и тут.
Стоял Linux Mint и Windows 7.
Слетела винда.
Переустановил Windows и затерся grub. Можно ли без переустановки восстановить загрузочный сектор для linux ?
Ответ
Нужно загрузиться с LiveCD, далее смонтировать корневой раздел установленной Linux системы, например, в папку /mnt Станем суперпользователем $ sudo su
Узнаем какие Linux увидел разделы и файловые системы # fdisk -l /dev/sda
# blkid
# lsblk
Монтирование корня # mount /dev/sda3 /mnt
Где sda3 - раздел с корневой файловой системой установленного Linux. Если содержимое /boot было расположено в отдельном от корневой файловой системы разделе, его тоже необходимо монтировать. Но в начале конечно всегда монтируется корень, после уже файловая система с boot в /mnt/boot Необходимо, если после монтирования корня каталог /boot установленной системы пуст. Пример монтирования /boot. # mount /dev/sda4 /mnt/boot/
Потом выполнить монтирование виртуальных ФС # mount --bind /dev /mnt/dev
# mount --bind /dev/pts /mnt/dev/pts
# mount --bind /proc /mnt/proc
# mount --bind /dev /mnt/dev
# mount --bind /sys /mnt/sys
Сменим текущий корень # chroot /mnt
Вы окажетесь уже в вашей старой системе, после этого выполнить # grub-install
# update-grub2
Выйдем из корня установленной системы # exit
Первая команда установит загрузчик stage1 grub2 в MBR, вторая обновит список загрузки - выполнит поиск систем и добавит их в меню загрузки. Далее необходимо размонтировать все файловые системы в обратном порядке # umount /mnt/sys
# umount /mnt/dev
# umount /mnt/proc
# umount /mnt/dev/pts
# umount /mnt/dev
# umount /mnt/
Далее выключите компьютер. Включите. Установите загрузку с жесткого диска. # reboot
Чесно, не зря пишут, что это сложная тема для понимания. Я не понял, как и большинство.
Где использовать вот эту штуку?
Пример:
.directive('clickable', function() { return {
restrict: "E", link: function($scope, element, attrs) {
element.bind('click', function() {
$scope.$apply(function() {
$scope.user++;
$scope.bar++;
});
console.log('1') });
}
} });
Без обертки $scope.$apply() пример работать не будет.
Не знаю, нашел такую заметку:
Важно: любые события браузера вызываются вне области видимости AngularJS, поэтому внутри ваших обработчиков таких событий необходимо вызывать $scope.$apply
Ответ
Так, а что конкретно не понятно? Функции $apply/$digest запускают dirty-check, и если данные в $scope изменились, то обновляют view, вот и вся магия. Когда вы изменяете данные внутри angular, например, на ng-click, он сам вызывает метод $apply, если ваш код выполняется не через angular, то нужно запустить dirty-check руками. Вот очень приблизительные примеры:
ng-click
внутри себя angular, заменил это конструкцию на:
jqLite('button').on('click', function (evt) {
evt.preventDefault(); $scope.counter++;
$scope.$apply();
});
или
$timeout(function () { $scope.foo = "bar"; }, 100); // эквивалентна
setTimeout(function () {
$scope.foo = "bar";
$scope.$apply();
}, 100);
Всё это очень примерно, но суть в том, что когда вы используете биндинг или методы angular, он за вас вызывает $apply/$digest, вот и всё, ничего сложного тут нет.
Можно ли полагаться на то, что JVM «умным образом» разрешает диапазон "а-я" или "a-z" в регулярном выражении и добавляет в него все символы некоторого алфавита, который начинается на «а» и заканчивается на «я»? Ответ: нет, диапазон читается буквально, и это можно подтвердить экспериментом Символы Ё и ё не попадают в диапазон юникода, в котором лежат все кириллические символы русского языка. То же самое верно для существенной части других алфавитов: буквы в Unicode идут не подряд. Предлагаю отвлечься от особенностей кириллицы и подумать об абстрактном "a-z", где "a" и "z" — первая и последняя буква какого-то алфавита. Есть ли в Java готовое решение для того, чтобы описать все "родные" буквы в заданной локали? Ответ: в Java нет, но есть в ответе к этому вопросу Нашел про поддержку локалей, но не вполне представляю, как это можно применить в регулярном выражении. Логично бы ожидать character class, какой-нибудь \p{locale_Ru_Ru}, но не нахожу. Навеяно этим ответом к вопросу «Как определить не русский текст?»
Ответ
Регулярки просто включают диапазон между порядковыми значениями символов. Полный кириллический диапазон безусловно включает Ёё и многое другое. Так что, чтобы собрать базовую кириллицу, достаточно задать диапазон вида [\x400-\x4ff] (не уверен что точный синтаксис для этого формата в Java).
Ранее считал, что переопределять Equals для своих классов можно и нужно. Но натолкнулся на иную информацию, что переопределение может привести к проблемам с некоторыми коллекциями.
Когда следует переопределять object.Equals() для своих классов?
Неужели, если хочется сравнить на эквивалентность согласно сущности два объекта своих классов, нужно создавать отдельный метод?
А как быть со сторонними классами? Получается они не поставляют средств сравнения на эквивалентность сущностей?
Что я понимаю под эквивалентностью сущностей. Допустим есть класс public class Country
{
public Country (string name)
{
this.name = name;
}
private readonly string name;
public string Name { get {return name;}}
} public void Main()
{
var c1 = new Country("Россия");
var c2 = new Country("Россия");
}
так вот c1 и с2 для меня эквивалентны, т.к. не может быть двух стран в моём мире, с одинаковым названием. Просто так получилось, что мы создали два экземпляра, но они идентичны по своей сути..
Ответ
Как известно, .NET по умолчанию сравнивает объекты ссылочных типов по ссылкам, а объекты значимых типов -- побитово (читай, по значению). К чему это приводит в вашем примере? К тому, что c1 и c2 считаются неравными. С т.з. бизнес-логики вы правильно заметили, что они равны, однако среда ничего не знает о бизнес-логике. Отсюда выводы:
Метод Equals() надо переопределять там, где требуется, чтобы объекты считались равными по какому-то определенному правилу. В частности, это нужно, когда вы используете объекты типа в качестве ключей словаря, элементов хэш-сета, а также в качестве элемента какой-либо коллекции и вызываете метод Contains(). Также стоит заметить, что в пару к Equals() нужно переопределять и метод GetHashCode()
Да, нужно. Потому что правила равенства двух объектов одного типа -- это, грубо говоря, бизнес-правила, то, что относится к вашему приложению. Среда исполнения о них ничего не знает, но о них знаете вы как разработчик.
Для кастомного сравнения экземпляров сторонних классов используется интерфейс IEqualityComparer и его реализации. В BCL включены некоторые готовые реализации (например, для сравнения строк без учета регистра). В большинстве случаев вам потребуется создавать свой компаратор.
Зачем нужен данный синтаксис, ведь тип результата не вычисляется автоматом? auto foo(int arg) -> int {}
Ответ
Этот синтаксис появился в результате включения в стандарт C++ лямбда-выражений. Лямбда-выражение может быть записано, например, как, auto foo = [](int arg) -> int { /*...*/ };
Это лямбда-выражение может быть преобразовано в функцию, имеющую тип int( int ) Этот синтаксис переняли для объявления функций. У функции в ее начале должен присутствовать спецификатор(ы) типа возвращаемого выражения. Так как реальный тип возвращаемого значения указывается после списка параметров, то в качестве спецификатора возвращаемого значения в объявлении функции используется спецификатор auto В приведенном вами примере большого смысла так объявлять функцию не имеется. Но иногда тип возвращаемого значения может зависеть от типа вычисления сложного выражения, определить который программисту самостоятельно бывает трудно, да и это может привести к ошибке. Поэтому этот синтаксис удобен, например, при объявлении шаблонных функций. Рассмотрите следующую демонстрационную программу. #include template
auto foo(const T &x, const U &y) -> decltype( x + y )
{
return x + y;
} int main()
{
int x = 10;
int y = 20; std::cout << typeid(foo(x, y)).name() << std::endl; long z = 30; std::cout << typeid(foo(x, z)).name() << std::endl; float f = 40; std::cout << typeid(foo(x, f)).name() << std::endl;
}
Вывод программы на консоль, например, в MS VC++ может выглядеть как int
long
float
Заранее сказать, какой будет тип возвращаемого выражения, невозможно. Он зависит от типов параметров функции и от типа вычисляемого выражения. Использование спецификатора типа auto в данном примере облегчает объявление функции.
В чем различие между этими определениями переменной: #define N 100
и const int n = 100;
Что из этих двух является более предпочтительным и в чем достоинства каждого?
Ответ
Это очень дискуссионный вопрос у всех. Но в целом, в с++ лучше использовать const везде, где это возможно. Плюсы:
на них действуют области видимости.
компилятор относится к ним как к обычными переменным, доступным только на чтение.
у них есть тип.
У define это все - недостатки. Они действуют от места определения и до ... конца. Хотя, где этот конец будет - ещё нужно хорошо подумать. Они могут переопределять друг дружку и иногда искать, где именно было в очередной раз переопределено - ещё то удовольствие. Компилятор часто выдает очень "загадочные ошибки". Классический пример с макросом min/max. Файл windows.h определяет их. И может быть очень весело. Детали - NOMINMAX Ещё у define есть большой недостаток - это то, что некоторые думают, что там есть скобки. А их нет. #define add(a,b) a+b if (add(x,y) * add(x,y)) {}
кажется, что будет посчитано (x+y) в квадрате. А на самом деле - .... на самом деле x+y + x*y. Но мы немного отвлеклись. Такого сделать обычным const уже нельзя. Но легко сделать inline функциями. И их результат будет предсказуемый. Поэтому:
eсли нужно просто определить константу - используйте const (даже само слово намекает).
eсли нужно определить макрос - используйте функции (если хочется интересней - используйте inline, но компиляторы сейчас достаточно умные).
если нужно усложнить код и добавить синтаскического сахара - тогда самое время использовать define.
UPD А ещё хорошо найти книгу Эффективное использование C++. 55 верных советов улучшить структуру и код ваших программ - Скотт Майерс и почитать второй совет (в любом случае - там всю книгу можно читать и читать).
Есть конструктор public CustomizedComparator(Comparator... comparators) {
this.comparators = comparators;
}
Вопрос в том, что значат эти три точки в нем?
Ответ
Это конструктор с переменным числом аргументов типа Comparator В вашем классе поле this.comparators вероятно имеет тип Comparator[] - то есть массив компараторов. Вызывать такой конструктор вы можете, например, такими способами: CustomizedComparator(); CustomizedComparator(comparator); CustomizedComparator(intCompataror, longComparator, stringComparator); и так далее. По сути это является синтаксическим сахаром для передачи массивов в методы/конструкторы.
Возник вопрос по логике кода. Почему компилятор не пропускает такой код? String testStr;
if (check > 0) {
testStr = "abc";
}
System.out.println(testStr != null ? testStr: "0");
При компиляции выдаётся ошибка:
Error:(134, 32) java: ... variable testStr might not have been initialized
Хотя вроде как логичным будет просто вывести "0" в случае, если testStr не было инициализировано... Какая тут логика?
Ответ
Есть два варианта интерпретации данного кода:
Программист хотел объявить переменную с каким-то значением, но допустил ошибку в коде: пропустил присвоение значения либо блок else. В этом случае компилятор поможет ему найти ошибку.
Программист полагает, что testStr будет инициализировано как null по умолчанию. В этом случае компилятор заставит программиста инициализировать переменную как null явно.
Разработчики Java пришли к выводу, что:
важно отловить возможные ошибки;
неудобства, связанные с инициализацией локальных переменных, незначительны.
Обязательная инициализация локальных переменных определена в спецификации Java
Chapter 16. Definite Assignment
Each local variable (§14.4) and every blank final field (§4.12.4, §8.3.1.2) must have a definitely assigned value when any access of its value occurs.
An access to its value consists of the simple name of the variable (or, for a field, the simple name of the field qualified by this) occurring anywhere in an expression except as the left-hand operand of the simple assignment operator = (§15.26.1).
For every access of a local variable or blank final field x, x must be definitely assigned before the access, or a compile-time error occurs.
Перевод (из книги «Язык программирования Java SE 8. Подробное описание»)
Глава 16. Определенное присваивание
Каждая локальная переменная (§14.4) и каждое пустое final-поле (§4.12.4, §8.3.1.2) должны иметь определенно присвоенное значение при любом обращении к их значениям.
Обращение к их значениям состоит из простого имени переменной (или, в случае поля, простого имени поля, квалифицированного ключевым словом this), находящегося в любом месте выражения, за исключением левого операнда оператора присваивания = (§15.26.1).
Для каждого обращения к локальной переменной или к пустому final-полю x, x должно быть определенно присвоено до этого обращения, иначе генерируется ошибка времени компиляции.
Посмотрите также обсуждения этого вопроса в английской версии:
Why are local variables not initialized in Java?
Why must local variables, including primitives, always be initialized in Java?
int[] indexOfTask = new int[0];
С какой целью такая возможность поддерживается компилятором?
Ответ
Есть такая замечательная книга "Effective Java" Джошуа Блоха, содержащая обширный список рекомендаций по проектированию и разработке эффективных, надёжных и легкосопровождаемых программ. Одна из рекомендаций звучит как "Возвращайте массивы и коллекции нулевой длины, а не null". Например, в классе java.io.File есть метод listFiles(), который возвращает массив файлов каталога. Представьте, как неудобно было бы, если бы он не смог вернуть массив нулевой длины для пустых каталогов! Пришлось бы вместо лаконичного for (File file : dir.listFiles()) {
...
}
делать File[] files = dir.listFiles();
if (files != null) {
for (File file : files) {
...
}
}
Как известно, кириллица в именах переменых это плохо. А почему? Ну, кроме известного довода, что "а если вы будете работать с иностранными программистами?"
P.S. Предположим, что речь идет о языке полностью поддерживающем Юникод.
Ответ
Даже без иностранных программистов можно найти несколько относительно веских причин:
Русские слова обычно длиннее английских ("получить" - "get", "страница" - "page", ну и так далее). Это, конечно, не всегда так, но в целом - соблюдается
Необходимость постоянного переключения раскладки
Каша из русских и английских слов визуально плохо выглядит
Здравствуйте! Всегда считал, что агрегация — это синоним композиции, однако наткнулся на блог в интернете, где приводятся отличия композиции от агрегации Мне это снесло крышу. Поясните, пожалуйста, плюсы/минусы и того и другого на небольших примерах. Как это влияет на расширяемость, тестируемость и т. д.
Ответ
Существует несколько видов взаимодействия объектов, объединенных под общим понятием "Has-A Relationship" или "Part Of Relationship". Это отношение означает, что один объект является составной частью другого объекта. Существует два подвида этого отношения: если один объект создает другой объект и время жизни "части" зависит от времени жизни целого, то это называется "композиция", если же один объект получает ссылку (указатель) на другой объект в процессе конструирования, то это уже агрегация. Давайте рассмотрим пример из .NET Framework, чтобы увидеть, какие ограничения/последствия несут эти отношения: StringWriter + StringBuilder Класс StringWriter - это специализированная версия класса TextWriter, которые активно используются при сериализации и для получения текстового представления объектов. Конкретно StringWriter создает строковое представление объекта или графа объектов и опирается на экземпляр StringBuilder в своей работе. Т.е. мы можем сказать, что 'StringWriter HAS A StringBuilder' или 'StringBuilder is part of StringWriter'. Теперь давайте посмотрим, как решить, должен ли StringWriter получать экземпляр StringBuilder-а извне или создавать его? С одной стороны, нам, как клиенту класса StringWriter часто бывает все равно, что именно используется внутри этого класса для получения строкового представления. Это значит, что с точки зрения простоты использования лучше, чтобы StringWriter создавал экземпляр StringBuilder-а самостоятельно. Но, с другой стороны, конкретный объект StringWriter-а может отвечать лишь за получения части строкового представления, а другая часть строки может вычисляться другим способом. С этой точки зрения, лучше, чтобы StringWriter принимал экземлпяр StringBuilder-а в конструкторе. Это же справедливо и для высоконагруженных систем, в которых разумно использование пула объектов. Поскольку StringWriter - это библиотечный класс, который должен поддерживать оба сценария, то у него есть перегруженные версии конструктора: один из них создает StringBuilder внутри, а другой - принимает его снаружи. Другими словами, выбор между композицией и агрегацией основан на соблюдении балланса между различными требованиями в дизайне: Композиция: объект A управляет временем жизни объекта B Плюсы:
Композиция позволяет скрыть отношение использования объектов от глаз клиента.
Делает API использования класса более простым и позволяет перейти от использования одного класса, к другому (например, StringWriter мог бы поменять реализацию и начать использовать другой тип, например CustomStringBuilder).
Минусы:
Отношение достаточно жесткое, поскольку один объект должен уметь создавать другой: он должен знать конкретный тип и иметь доступ к функции создания. Композиция не позволяет использовать интерфейсы (без привлечения фабрик) и требует, чтобы класс имел доступ к конструктору другого класса: представьте, что конструктор StringBuilder-а является внутренним или же это интерфейс IStringBuilder и только клиенский код знает, какой экземпляр должен использоваться здесь и сейчас.
Агрегация: объект А получает ссылку на объект B Плюсы:
Более слабая связанность между объектом и его клиентом. Теперь мы можем использовать интерфейсы и одному объекту не нужно знать, как именно создавать другой объект.
Большая гибкость. Вытекает из первого пункта
Минусы:
Выставление наружу деталей реализации. Поскольку клиент класса должен предоставить зависимость в момент создания объекта (передать экземпляр StringBuilder-а в момент создания StringWriter-а, то сам факт этого отношения становится известен клиенту.
Из первого пункта вытекает увеличение сложности в работе клиентов, а также большая "жесткость" решения в долгосрочной перспективе. Теперь автор класса TextWriter уже не может принять решение самостоятельно и перейти от StringBuilder-а к чему-то другому. Да, можно "добавить еще один уровень абстракции" и выделить интерфейс IStringBuilder, но разорвать это отношение совсем будет невозможно без поломки всех существующих клиентов.
В заключении: дизайн - это поиск компромисса между различными факторами. Композиция проще с точки зрения клиентов класса, но налагает определенные ограничения: "целое" должно уметь создавать "составную часть". Агрегация гибче, но налагает другие ограничения: теперь "целое" не скрывает о существовании "составной части", а значит и не сможет заменить ее на другую "составную часть" в будущем. P.S. Если очень хочется использовать пример из реального мира, то для объяснения композиции и агрегации может подойти ... отвертка. Если отвертка цельная, т.е. ручка и насадка намертво связаны друг с другом, то мы имеем отношение композиции. Если же насадка съемная и может существовать без ручки или же использоваться с другой ручкой, то мы имеем отношение агрегации
На данный вопрос уже ответили:
Книги и учебные ресурсы по C#
1 ответ
Друзья! Подскажите, пожалуйста, книгу по программированию ASP.NET MVC 4 на VS 2012 на русском языке, если таковые уже имеются. Спасибо!
Ответ
Могу посоветовать онлайн-книгу по ASP.NET MVC 4 - http://metanit.com/sharp/mvc/index.php
больше на русском не встречал.
На английском уже есть три книги. Кроме вышеописанной в предыдущем посте:
Programming ASP.NET MVC 4: Developing Real-World Web Applications with ASP.NET MVC
и
ASP.NET MVC 4 in Action
Первая печатная книга на русском языке по этой теме выйдет только в следующем году
Не могу разобраться, как перегрузить оператор присваивания. С бинарными операторами более-менее всё понятно, там хотя-бы два операнда, а вот с этим - никак. Не могли бы вы привести пример перегрузки "=", и разъяснить что где делает, и результат перегрузки? Например перегрузить так, чтобы он к присваиваемому числу прибавлял + 5, или что-то вроде, и показать, к чему и от чего присваивается и к чему где прибавляется.
Ответ
Vector& Vector::operator=(Vector& v)//перегрузка
{
x=v.x;y=v.y;z=v.z;
return *this;//возвращаем ссылку на текущий объект
}
Не знаю, что вызвало сомнения и вопросы. Главное после присваивания вернуть ссылку на текущий объект.
Хотелось бы узнать каковы области применения языков Си и Си++ и для каких платформ чаще их используют?
Ответ
Эти языки используются там, где нужно максимальное быстродействие, экономия памяти и "близость" к железу. Особенно это относится к Си. С++ уровнем чуть повыше и у программ на нем требования к ресурсам чуть больше.
В папке с git-ом случайно нажал на git init , в итоге теперь когда делаю git status у меня все файлы отображаются как измененные. В git log последние коммиты остались. Как отменить действие команды git init?
Ответ
Если просто случайно создали репозиторий, то нужно удалить папку .git в корне. Это полностью уничтожит репозиторий и, разумеется, отменит то, что сделал git init. Через *nix-консоль это делается так: rm -r .git
Если же Вы сделали git init в уже существующем репозитории, то бояться нечего
Running git init in an existing repository is safe. It will not overwrite things that are already there. The primary reason for rerunning git init is to pick up newly added templates (or to move the repository to another place if --separate-git-dir is given).
Не знаю, корректно ли на этом сайте такие вопросы задавать... В общем я не уверен что код ниже верно написан. Свою задачу он выполняет, проверял неоднократно. Однако меня гложут сомнения в том, насколько эта реализация может считаться правильной. Быть может на C# такого рода задачу принято реализовывать иначе? Хотелось бы получить критику и разъяснения. Сама программа - аудио конвертер. Ищет в папке подходящие файлы и запускает внешний, консольный конвертер для их преобразования в wav. public partial class Form1 : Form
{
static object locker = new object();
string[] findFiles;
int fifi = -1; public Form1()
{
InitializeComponent();
Conv();
{ async void Conv()
{
findFiles = Directory.GetFiles(Application.StartupPath, "*.ape", SearchOption.AllDirectories).Union(Directory.GetFiles(Application.StartupPath, "*.ogg", SearchOption.AllDirectories)).ToArray(); // Поддерживаем не более 8 ядер.
int p;
if (Environment.ProcessorCount < 8)
p = Environment.ProcessorCount;
else
p = 8; int t;
// Если количество файлов больше чем ядер, то устанавливаем столько потоков, сколько ядер.
if(findFiles.Length > p)
t = p;
else // Если файлов меньше чем ядер, то потоков устанавливаем сколько файлов.
t = findFiles.Length; // Устанавливаем количество потоков.
Task[] tasks = new Task[t]; // Запускаем потоки.
for (int i = 0; i <= p - 1; i++)
{
if(i <= findFiles.Length - 1)
{
tasks[i] = new Task(() => ConvertDoWork(++fifi));
tasks[i].Start();
}
} // Ждём выполнения всех задач.
await TaskEx.WhenAll(tasks); Application.Exit();
} int p, pc;
public void ConvertDoWork(int num)
{
int n = num; if ((findFiles.Length == 0) || (n > findFiles.Length))
return; string s = findFiles[n]; ProcessStartInfo startInfo = new ProcessStartInfo();
if (Path.GetExtension(s).Equals(".ogg"))
{
startInfo.FileName = "oggdec.exe";
startInfo.Arguments = "-Q \"" + s + "\"";
}
else
if (Path.GetExtension(s).Equals(".ape"))
{
startInfo.FileName = "MAC.exe";
startInfo.Arguments = "\"" + s + "\" \"" + Path.ChangeExtension(s, ".wav") + "\" -d";
}
startInfo.WorkingDirectory = Application.StartupPath;
startInfo.CreateNoWindow = true; Process processReg = new Process();
processReg.StartInfo = startInfo;
processReg.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
processReg.Start();
processReg.WaitForExit(); lock (locker)
File.Delete(s); int percentComplete = (int)Math.Round((double)(100 * n) / findFiles.Length);
pc = percentComplete / 10; try
{
this.Invoke((MethodInvoker)delegate
{
progressBar1.Value = percentComplete; // Если не выбрано не отображать прогресс, то отображаем всплывашку.
if ((notifyIcon1.Visible) && (!chkNotNotify.Checked) && (!pc.Equals(p)))
{
notifyIcon1.ShowBalloonTip(300, "Прогресс", "Выполнено " + percentComplete + "% работы", ToolTipIcon.Info);
p = pc;
} }); }
catch (System.Exception ex)
{ } lock (locker)
++fifi;
if (fifi < findFiles.Length)
ConvertDoWork(fifi);
}
Ответ
1. Слишком много переменных уровня класса. Каждую из них надо отдельно перепроверять - а мне лень. Куда безопаснее локальные переменные и параметры функции. 2. Переменная fifi используется опасным образом. Лучше от нее вовсе отказаться, а распараллеливание делать другими методами. Для распараллеливания через задачи я сам использую и всем рекомендую вот такую конструкцию: await TaskEx.WhenAll(
from file in findFiles
select Task.Run(() => ConvertDoWork(file))
);
Вам, я так понимаю, нужно еще ограничить число число одновременно выполняемых задач числом ядер. Вручную это можно сделать вот так: class LimitedConcurrencyGuard {
private readonly object _lock = new object();
private readonly Queue> queue = new Queue>();
private int slots; public LimitedConcurrencyGuard (int slots) { this.slots = slots; } public async Task AcquireSlot() {
TaskCompletionSource