Страницы

Поиск по вопросам

пятница, 29 ноября 2019 г.

Как сделать волнистую полоску на css?

#css #css3


Подскажите, как можно сделать вот такую полоску лесенкой с помощью css


    


Ответы

Ответ 1



На html и css *{ box-sizing:border-box; } body{ margin:0; } .angles{ display:flex; align-items:flex-start; list-style:none; padding:0 0 0 10px; } .angles li{ width:30px; height:30px; border:4px solid yellow; border-left:none; border-bottom:none; transform:rotate(-37deg) skewX(14deg); transform-origin:center; margin-right:14px; }
На svg #angles{ stroke-width:3px; stroke:yellow; fill:none; }

Ответ 2



body { background: green; } ul { display: flex; list-style: none } .a::before { padding: 0; margin: 0; content: ""; position: relative; display: block; background: yellow; width: 17px; height: 2px; border-radius: 100px; transform: rotate(-20deg) } .a::after { padding: 0; margin: 0; content: ""; border-radius: 100px; position: relative; top: -2px; left: 15px; display: block; background: yellow; width: 17px; height: 2px; margin-right: 12px; transform: rotate(20deg) }
Если угол наклона линий захотите поменять.

Ответ 3



Конечно, не помешало бы сглаживание, но можно с помощью linear-gradient: div { position: relative; height: 100px; background-color: #ffd800; background-size: 32px 20px; background-position: 0 0, 0 0, -16px 0, 16px 0px; background-image: linear-gradient(35deg, #fff 11px, transparent 0), linear-gradient(-35deg, #fff 11px, transparent 0), linear-gradient(-145deg, #fff 11px, transparent 0), linear-gradient(145deg, #fff 11px, transparent 0); }
P.S. Если угол 45deg то артефактов нет.

Как парсить аргументы командной строки?

#c_sharp #visual_studio #консоль


Пишу консольное приложение которое должно принимать более 5 параметров. При этом
есть обязательные параметры есть не обязательные, одни параметры должны работать только
с другими и т.д.. Я уже погряз в различных if..else if..else. Как облегчить себе жизнь?
Есть ли рекомендации и стандартные приёмы по работе с аргументами командной строки?
    


Ответы

Ответ 1



Если параметров много, лучше всего вынести их разбор в отдельный класс или набор классов. Когда if/else образуют сложную структуру, можно использовать «повышенную декларативность» C# и описывать структуру команд, например, так: var commandLinePattern = Command.WithName('add') .HasOption('-fileName') | Command.WithName('help') .HasParameter("CommandName"); Конечно, это потребует определённой изобретательности при проектировании, так что ниже изложу подробнее. Следующим шагом мы опишем наши команды: public interface ICommand { void Run(); } public HelpCommand : ICommand { public string CommandName { get; set; } public bool Verbose { get; set; } public int PageSize { get; set; } public void Run() { if (CommandName == "add") { Console.WriteLine("Help on the ADD command"); } . . . } } Шаблон командной строке (переменная commandLinePattern в первом примере) можно применить к конкретной строке параметров, чтобы построить экземпляр конкретного класса команды, и заполнить его свойства, использую рефлексию: var command = commandLinePattern.Parse(args); command.Run(); UPDATE Итого, получается приблизительно такой код: static class Program { private static readonly commandLinePatterm = Command.WithName('add') .HasOption('-fileName') .HasOption('-move') | Command.WithName('help') .Parameter("CommandName"); static void Main(string[] args) { var command = commandLinePattern.Parse(args); command.Run(); } } UPDATE «для новичка» Немного о том, как реализовать всю эту красоту. Наше чудо по внешнему виду и внутреннему устройству очень напоминает регулярные выражения: сначала мы описываем некий шаблон аргументов командной строки, и затем применяем его к реальным аргументам. Результатом такого применения будет объект, который можно будет выполнить. Назовём его командой. Название команда возникло не просто так — это один из паттернов проектирования, описанный в классическом труде банды четырёх. Я не знаю, какие командные строки вам приходится разбирать, поэтому сделаю несколько предположений: Программа может выполнить за один запуск одну и только одну команду. Команда идёт первой в командной строке. Команда не требует префиксов, таких как дефис или косая черта. За командой могут следовать один или несколько параметров. Параметры могут быть именованными и безымянными. Именованные параметры имеют префикс, например, дефис. Именованные параметры могут иметь значение, в этом случае оно отделяется от имени двоеточием. Приблизительно такие правила используются в большом количестве утилит, например, в архиваторах pkzip, arj и rar; в утилитах контроля версий git и hg — то есть этих двух правил действительно хвататет для широкого спектра задач. arj add archive *.c -m0 arj — это имя программы, add — команда, archive (имя архива) и *.c (что архивировать) — безымянные параметры; -m — именованный параметр (опция), 0 — значение параметра. В arj значение параметра не требуется отделять символом : или =. Мы пойдём другим путём, исключительно для из-за того, что пример демонстрационный. Такой шаблон параметра командной строки может быть описан простым классом: public class CommandLinePattern { public string Name { get; set; } public List Parameters { get; set; } public List Options { get; set; } } Например, команда help может иметь такой шаблон program Help CommandName [-Verbose] [-PageSize:num] Которому соответствует экзмепляр класса CommandLinePattern: var pattern = new CommandLinePattern { Name = "Help", Parameters = new List { "CommandName" }, Options = new List { "Verbose", "PageSize" }, }; Нам нужно решить две задачи: построить такой шаблон, и применить его. В коде выше мы воспользовались статическим классом Command для того, чтобы начать конструировать шаблон: public static class Command { public static CommandLinePattern WithName(string name) { return new CommandLinePattern { Name = name, Parameters = new List(), Options = new List(), }; } } Остальные методы конструирования разместим непосредственно в классе CommandLinePattern: public CommandLinePattern HasOption(string name) { Options.Add(name); return this; } public CommandLinePattern HasParameter(string name) { Parameters.Add(name); return this; } Благодаря конструкции return this; мы можем строить объект последовательно, увязывая методы в цепочку: var pattern = Command.WithName("Help") .HasParameter("CommandName") .HasOption("Verbose") .HasOption("PageSize"); Таким образом мы описываем шаблоны команды. Теперь решим вторую задачу — разбор командной строки и создание объекта-команды. В классе CommandLinePattern реализуем метод TryParse, который будет пробовать разобрать командную строку и в случае успеха создавать объект, реализующий такой интерфейс ICommand: public virtual bool TryParse(string[] args, out ICommand result) { result = null; // Конечно, наш шаблон не может соответствовать пустой командной строке. if (args.Length == 0) return false; // И он не может соответствовать какой-то другой команде. if (args[0] != Name) return false; var properties = new Dictionary(); var nextParameterIndex = 0; for (int i = 1; i < args.Length; i++) { if (args[i].StartsWith("-")) { var parameterWithoutHyphen = args[i].Substring(1); var nameValue = parameterWithoutHyphen.Split(':'); if (nameValue.Lenth == 1) properties.Add(nameValue[0], null); else properties.Add(nameValue[0], nameValue[1]); } else { var name = Parameters[nextParameterIndex]; nextParameterIndex++; var value = args[i]; properties.Add(name, value); } } // Для команды с имененем Help мы найдём класс HelpCommand: var className = Name + "Command"; var type = Type.GetType(className); // И создадим его экземпляр: result = (ICommand)Activator.CreateClass(type); // Теперь значения всех параметров запишем в свойства // только что созданного экземляра: foreach (var property in properties) { var name = property.Key; var value = property.Value; type.GetProperty(name) .SetValue(result, value); } return true; } public virtual ICommand Parse(string[] args) { ICommand result; if (TryParse(args, out result)) return result; throw new FormatException(); } Имейте в виду, что такая запись значений будет работать только со строковыми свойствами — в реальной программе вам потребуется конвертировать строковые значения в типы свойств. Теперь у нас уже всё готово. Мы можем написать наш разбор параметров, но «для красоты» сделаем ещё один финальный штрих. Создадим класс, который позволит объединить два шаблона и проверять сначала левый, а затем правый: public class OrCommandLinePattern : CommandLinePattern { private readonly CommandLinePattern left; private readonly CommandLinePattern right; public OrCommandLinePattern(CommandLinePattern left, CommandLinePattern right) { this.left = left; this.right = right; } public override bool TryParse(string[] args, out ICommand result) { if (left.TryParse(args, result)) return true; return right.TryParse(args, result); } } В базовый класс добавим реализацию оператора ИЛИ: public static CommandLinePattern operator |(CommandLinePattern left, CommandLinePattern right) { return new OrCommandLinePattern(left, right); } Теперь мы можем объединить несколько паттернов с помощью вертикальной черты: var commandLinePattern = Command.WithName('add') .HasOption('-fileName') | Command.WithName('help') .HasParameter("CommandName"); И в конце запускаем парсинг с помощью вызова одного единственного метода: var command = commandLinePattern.Parse(args); Результатом работы парсера будет экземпляр класса, реализующего интерфейс ICommand с заполненными свойствами. Нам остаётся только запустить его: command.Run();

Ответ 2



Отличный парсер аргументов командной строки. Единственный минус - придётся написать небольшую прослойку на F# (~20-30 строк). Действительно небольшую - можно посмотреть туториал.

Содержит ли данный код UB?

#c++ #операторы


Содержит ли данный код UB?     

int i = 6;
i = 7, ++i, i++;

    


Ответы

Ответ 1



Такие операторы, как оператор запятая, оператор логического И (&&) и оператор логического ИЛИ (||) перед вычислением следующего операнда выполняют все побочные эффекты, связанные с выражением для первого операнда. Например, вы можете написать std::cout << ( i++, i++, i++ ) << std::endl; или if ( i++ > 0 && i++ < 10 ) { /* ... */ } или if ( i++ == 0 || i++ % 3 == 0 ) { /* ... */ } То же самое относится к спискам инициализации в C++. Например, int a[] = { i++, ++i }; Или в конструкторе класса struct A { int x; int y; A( int i ) : x( i++ ), y( ++i ) { //,,, } }; Если поведение перечисленных операторов относительно побочных эффектов одинаково и в C++, и в C, то относительно списков инициализации между этими двумя языками имеется важное отличие. В C порядок вычисления побочных эффектов инициализаторов в списке инициализации не определен. Из стандарта C (6.7.9 Initialization) 23 The evaluations of the initialization list expressions are indeterminately sequenced with respect to one another and thus the order in which any side effects occur is unspecified.152 Сравните эту цитату с цитатой из стандарта C++ (8.5.4 List-initialization) 4 Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions (14.5.3), are evaluated in the order in which they appear. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list. [Note: Thisevaluationorderingholdsregardlessofthesemanticsoftheinitialization; forexample, itapplies when the elements of the initializer-list are interpreted as arguments of a constructor call, even though ordinarily there are no sequencing constraints on the arguments of a call. —end note]

Ответ 2



Нет, никакого UB тут нет, если учесть, что группировка операторов и операндов в этом выражении имеет следующий вид (i = 7), (++i), (i++); Оператор "запятая" упорядочивает (sequences) как вычисление значений своих операндов, так и выполнение их побочных эффектов. (Выражаясь старой терминологией, оператор "запятая" является точкой следования). Сначала будет вычисляться левый операнд, а затем - правый. Причем все побочные эффекты вычисления левого операнда возымеют место еще до того, как начнется вычисление правого операнда. 5.19 Comma operator [expr.comma] 1 [...] A pair of expressions separated by a comma is evaluated left-to-right; the left expression is a discarded-value expression. Every value computation and side effect associated with the left expression is sequenced before every value computation and side effect associated with the right expression. [...]

Ответ 3



С чего бы это? Операция , однозначно определяет порядок (слева направо) вычисления выражений, результатом будет значение последнего выражения. У вас i станет равно 9.

Восстановление объектов в C#

#c_sharp


В своей книге Троелсен пишет:


  ...детали, касающиеся сборки мусора (вроде слабых ссылок и
  восстановления объектов), остались не рассмотренными...


Где бы можно в доступно виде прочитать про это? Гуглил "Object resurrection", но
ничего хорошего на русском вообще не нашел.
    


Ответы

Ответ 1



Ну, раз не нашли, давайте я расскажу. Объекты делятся на те, которым нужна финализация (то есть, те, у которых есть деструктор-финализатор), и те, которые обходятся без неё. Вторых объектов гораздо больше: обычно вам не нужен деструктор в объекте. Такие объекты нам не интересны, пропускаем их. Итак, что происходит во время пробега сборщика мусора? Он находит все объекты, на которые нету корневых ссылок (возможно, косвенных) и ссылок из «живых» локальных переменных. Эти объекты помещаются в список на уничтожение. Теперь, те из них, которым нужна финализация¹, перемещаются в отдельную очередь для финализации. Остальные объекты просто уничтожаются². Заметьте, что очередь финализации является корневым объектом, поэтому элементы, которые уже там лежат, не являются кандидатами на удаление. Отдельный поток³ следит за очередью финализации, и понемногу финализирует объекты оттуда. Это значит, что у этих объектов вызывается финализатор. После этого объект удаляется из очереди, и таким образом подлежит повторной сборке мусора. Больше очередь финализации не ссылается на объект, и он в принципе должен быть собран сборщиком мусора при следующем пробеге. Однако, финализатор — это такая же функция⁴. И эта функция может сделать что-то, что сделает объект недоступным для сборщика мусора! Например, поместит ссылку на этот объект в глобальную переменную. Таким образом, у нас получается воскресший объект, который к тому же уже профинализирован! CLR запоминает, что объект уже был финализирован, и больше не будет пытаться его финализировать снова. (Вы можете сбросить этот флаг при помощи GC.ReRegisterForFinalize, устроив потенциально бесконечный цикл.) Заметьте, что даже если вы полностью контролируете код своего объекта, вы не можете предотвратить «оживление» вашего объекта другим объектом! Смотрите: если другой финализируемый объект содержит ссылку на ваш, и они оба попадают в очередь финализации, и этот самый другой объект в результате финализации оживает, то он «тянет за собой» с того света назад на этот все объекты, доступные по его ссылкам! В частности, и ваш объект. Несмотря на то, что восстановление объектов, пойманных сборщиком мусора, возможно, эта техника очень сложная, опасная и практически на грани фола. Поэтому я бы предостерёг от её использования для целей, отличных от простого развлечения. Если вам захотелось оживить объект, возможно, вам просто нужен явно управляемый пул объектов? PS: Учитывая сложности корректной финализации, стоит просто избегать её по возможности. Если вы используете финализатор для работы с неуправляемыми ресурсами, то достаточно вместо IntPtr использовать SafeHandle, и необходимость в финализации отпадёт. Обратите внимание, что не стоит доверять финализатору ещё и по такой причине: функции GC.SuppressFinalize() и GC.ReRegisterForFinalize() для вашего объекта может вызвать любой код! ¹ Вы можете, однако, запретить финализацию даже для объекта с финализатором при помощи метода GC.SuppressFinalize. Это полезно, например, если вы имплементируете IDisposable, и в методе Dispose подчищаете все ресурсы. ² Если только на них нету ссылок из объектов, помещаемых в очередь для финализации, т. к. эти объекты после помещения в очередь снова имеют корневую ссылку! ³ В текущей реализации подсистемы сборки мусора, разумеется. ⁴ С некоторыми предосторожностями: в финализаторе нужно с осторожностью работать, например, с управляемыми полями, потому что их содержимое может быть уже финализировано!

Ответ 2



На русском: Источники о сборке мусора в .NET Немного о сборке мусора и поколениях Слабые ссылки в .NET О сборке мусора и достижимости объектов На английском: When everything you know is wrong, part one When everything you know is wrong, part two Очень советую посмотреть статьи Эрика Липперта - там очень хорошо показывается, что всегда может что-то быть не так, как ты ожидаешь.

Конвертация массива string в массив int C# одной строкой кода

#c_sharp


Как можно конвертировать строку чисел, разделённых пробелом, в массив int одной строкой
кода?

Поделил на строки, но как конвертировать это в массив int, не создавая дополнительного
массива string, не знаю.

int [] Mas = textBox1.Text.Split(' ')

    


Ответы

Ответ 1



Попробуйте следующее int[] a = textBox1.Text.Split(' ').Select(x => int.Parse(x)).ToArray(); Правильнее будет написать int[] a = textBox1.Text.Split(' '). Where(x => !string.IsNullOrWhiteSpace( x )). Select(x => int.Parse(x)).ToArray();

Ответ 2



Раз уж пошел такой codegolf... короткий вариант без LINQ, если не нужно вырезать пробелы: Array.ConvertAll(text.Split(),int.Parse); чуть более длинный вариант для случая, когда нужно вырезать пробелы: Array.ConvertAll(Regex.Split(text,@"\s+"),int.Parse); Минимальные варианты через LINQ без/c RemoveEmptyEntries text.Split().Select(int.Parse).ToArray(); text.Split(new[]{' '},StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();

Ответ 3



int[] result = textBox1.Text.Split( new[]{" "}, StringSplitOptions.RemoveEmptyEntries ).Select(x => int.Parse(x)).ToArray();

Ответ 4



int[] a = textBox1.Text.Split(' ').Select(int.Parse).ToArray();

Как правильно использовать исключения

#c_sharp #исключения


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

catch (Exception ex)
   {
       // <сообщение>
   }


а не 

catch (DivideByZeroException)
   {
       // <сообщение про одно>     
   }
catch (FormatException)
   {
       // <сообщение про другое>     
   }
catch (ArithmeticException)
   {
       // <сообщение про третье>     
   }
catch (Exception ex)
   {
       // <сообщение>
   }


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

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

Так как поступать с исключениями в таких ситуациях? Определять "на глаз" в каком
месте обязательно нужно уведомлять о возможных причинах ошибки, а в каком достаточно
общего сообщения? Или есть какие-то уже сформулированные критерии по этому поводу?
Или по сути вообще может без разницы, и все эти рассуждения не имеют значения?
    


Ответы

Ответ 1



Вопрос конечно очень холиварный =) но тем не менее, поделюсь своими представлениями, ни в коей мере не претендуя на абсолютную истину. Любая программа, работающая в реальных условиях и окружении с участием пользователя или без, способна генерировать массу исключений по разным причинам. Исключение составляют учебно-олимпиадные программы, которые работают в "идеальных" условиях, т.е. входные данные жестко регламентированы и ошибка пользователя исключена условиями задачи. У каждого исключения может быть несколько причин для появления: Ошибка пользователя при вводе данных тем или иным способом. Исключения возникшие по этой причине ловить необходимо, чтобы сообщить пользователю о его ошибке и дать возможность повторить ввод данных или некоторый набор действий для продолжения работы программы. Ошибка возникшая по вине среды окружения, например операционной системы или другой программы или библиотеки с которой вам приходится взаимодействовать. Такие исключения, в среднем, ловить противопоказано, т.к. единственное что можно сделать в таком случае, это попытаться корректно завершить работу, однако даже это может привести к непредсказуемым последствиям и порче данных пользователя, что вряд ли обрадует последнего. Однако, если вы уверены что ошибка, вызвавшая исключение, безвредна для данных или само исключение несет сугубо информативный характер, как, например, исключения при попытке установить сетевое соединение или при работе с файлами, то такое исключение может быть поймано и обработано. Ошибка возникшая по вине самой программы или ее части, например "любимый" всеми NullReferenceException. Исключения подобного рода необходимы на этапе отладки. Ловить их в коде никакого смысла нет, т.к. в процессе отладки, в идеале, все места кода, где могут возникнуть исключения по вине программы, должны быть исправлены. Как временная мера, можно и поймать, но тут есть большой риск что эта временная мера так и останется навсегда костылем в коде. В целом, исключение генерируется тогда, когда исполняемый код не знает что делать в возникшей ошибкой. Я для себя вывел 3 простых правила по обработке исключений: Если можно исправить код так, чтобы исключение не возникало - исправляем код. Если не знаешь что делать с ошибкой которая стала причиной исключения, не лови его и дай программе упасть. Если уверен что знаешь что делать с ошибкой, ловим, заносим в логи, исправляем ошибку и бежим дальше либо падаем, тут уж по обстоятельствам.

Ответ 2



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

Ответ 3



Судя по описанию в исходном вопросе, ваш вопрос скорее -- как правильно обрабатывать исключения. (Потому что есть совсем другой вопрос -- как правильно выбрасывать исключения.) Есть общие правила, о которых тут уже говорили (и всегда говорят) -- не надо ловить все исключения, кроме как на самом верху, а там записывать их (логировать) для последующего анализа. Это правило становится понятным, когда увидишь какие исключения вообще могут выпадать. Например, ловить Out of memory или Thread abort вообще нет никакого смысла. Помимо этого, возникает чисто прикладной вопрос -- а какие исключения ловить в конкретном случае. Вызываем вот такой метод, и что нам от него ожидать? Если речь идёт о библиотеке .NET Framework или какой-то известной сторонней библиотеке -- можно почитать справку по методу (XML docs), там должно быть описано чего стоит ожидать. Но в общем случае -- приходится делать серию пробных запусков с ожидаемыми сценариями падений, и ставить отлов тех исключений что выпали.

Ответ 4



Смысл исключений — развести точку возникновения ошибки и точку её обработки. Иначе нету никакой разницы между исключением и возвратом кода ошибки. Поэтому отлов исключений обычно производится не везде, а в ключевых точках программы. Запустили логическую операцию — она либо выполнилась и произвела результат, либо выбросила исключение. Обычно в точке, где ловится исключение, вы не знаете точный список всех типов исключений (а в ситуации с динамическим кодом, например, с DI, можете вообще быть не в состоянии узнать). Поэтому в ключевых точках обычно стоит ловить достаточно общие виды исключений. (Но, разумеется, не все возможные.) С другой стороны, имеет смысл организовывать модули так, чтобы исключения, которые выбрасывает модуль, имели либо стандартный тип (ArgumentException, FileFormatException и т. п.), или наследовались от немногих общих корней. В этой ситуации вы можете поймать довольно исключение, залогировать его (эта информация важна для разработчика), и продолжать дальше выполнение программы. Или не продолжать, если сорвалась критическая операция — решать вам.

Зачем нужен фабричный метод?

#c_sharp #шаблоны_проектирования


Допустим есть вот такая реализация фабричного метода:

abstract class Creator
    {
        public abstract Product FactoryMethod();
    }

    class ConcreteCreatorA : Creator
    {
        public override Product FactoryMethod() { return new ConcreteProductA(); }
    }

    abstract class Product
    {}

    class ConcreteProductA : Product
    {}


Какая выгода нам от создания объекта через Creator, если точно так же можно его создать
через new? Когда нужно использовать именно фабричный метод, и какое преимущество нам
это может дать?
    


Ответы

Ответ 1



Выгод может быть много. Некоторые: Вы можете дать имя вашему конструктору. Например: Point PointCreator.FromPolar(double r, double phi) PointCreator.FromPolar читается намного лучше, чем new Point(1, 0). Раз уж вы даёте имя, вы можете иметь несколько конструкторов с одинаковыми сигнатурами: Point PointCreator.FromPolar(double r, double phi) { ... } Point PointCreator.FromCartesian(double x, double y) { ... } или например DateTime DateTime.FromSeconds(double seconds) { ... } DateTime DateTime.FromMilliseconds(double ms) { ... } Вы можете создавать объекты не данного типа, а любого производного, причём конкретный тип может быть скрыт внутри фабрики (так что у вашего остального кода не будет зависимости от этого конкретного типа). Вы можете сделать дополнительные действия после окончательного построения объекта. Например, вы можете зарегистрировать объект в списке всех активных объектов. С конструктором такое не очень удобно, т. к. вам придётся делать это либо в конструкторе базового класса, и выкладывать ссылку на недоконструированный объект (что может привести к понятным проблемам, если кто-то в этот момент обратится к объекту), либо дублировать код во всех потомках (что не всегда возможно, и непроверяемо, так что провоцирует баги). Или вы можете сделать дополнительную инициализацию свойств объекта, если вам это нужно: WebRequest InitWebRequest(string uri) { var request = WebRequest.Create(uri); request.Credentials = new NetworkCredential(Settings.Login, Settings.Password); return request; } Вы не можете сделать конструктор асинхронным, а фабричный метод — можете. В самом фабричном методе вы можете вызвать конструктор и async-метод для инициализации. async SerialDevice Create(PortInfo portInfo) { var device = new SerialDevice(portInfo); await device.Connect(); return device; }

Ответ 2



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

Отличие коллекций от массивов

#java #алгоритм


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


Чем коллекции лучше массивов?
В чем преимущества коллекций над массивами? 
Когда лучше использовать массивы, чем коллекции?

    


Ответы

Ответ 1



Мне кажется, что вы путаете понятия. Если вам достаточно функционала массива, то используйте его, проблем никаких. Но в коллекциях значительно больше возможностей найти что-то действительно подходящее под задачи. Классический алгоритм выбора коллекции (для Java под рукой нет, у кого есть замените, но идея от этого не изменится): При этом массивы здесь находятся в блоке array. vector - это уже динамический массив ближе к ArrayList<>. Безусловно любой алгоритм и любую структуру из коллекций можно реализовать самому, но зачем?.. Непосредственно по вопросам: Чем коллекции лучше массивов? В них больше функционала, делать это над массивами зачастую нецелесообразно (или плохое качество кода или долго реализовывать или требуют хорошего понимания алгоритмов). Когда лучше использовать массивы, чем коллекции? Когда нужно хранить набор данных фиксированного размера. Смотри картинку с выбором.

Ответ 2



Давайте по порядку: Чем коллекции лучше массивов? Если вы работаете с примитивными типами, и не хотите тратить время на boxing/unboxing, то массивы предпочтительнее. Но если вы используете обычные классы, то лучше воспользоваться коллекциями, потому что массивы коварианты. Т.е. с ними легко написать не type-safe код. Например, такой: Integer[] a1 = new Integer[10]; Object[] a2 = a1; a2[0] = "привет ArrayStoreException!"; При этом компилятор ни разу не скажет, что это не правильно. В чем преимущества коллекций над массивами? Все зависит сильно от ваших задач. В коллекциях много различных структур данных, с разными свойствами. Например, Set - множество уникальных элементов, TreeSet - множество уникальных отсортированных элементов, List - список, сохраняющий порядок вставки, и т.д. Тут нельзя дать определенный ответ, тут скорее вопрос о целесообразности применения. Если вам в какой то момент не будет хватать простого массива, то смело используйте collection. Когда лучше использовать массивы, чем коллекции? см. пункт 2.

Фабричный метод и абстрактная фабрика

#шаблоны_проектирования


Помогите разобраться.

Чем отличаются данные шаблоны? Когда лучше применять первый, а когда второй? 
    


Ответы

Ответ 1



Фабричный метод: есть некий класс, который выполняет свою специфическую функцию. Часть своей функциональности он делегирует внешнему интерфейсу, который инстанцируется через виртуальный метод этого класса. Наследники этого класса, перекрыв этот метод, могут вернуть другие реализации интерфейса, используемого основным алгоритмом класса. Абстрактная фабрика: класс / интерфейс, не содержащий собственной логики. Все его методы возвращают экземпляры других интерфейсов и вызываются внешними компонентами. Этот паттерн позволяет, подменив реализацию одного интерфейса, подменить набор реализаций ограниченного множества интерфейсов. Абстрактная фабрика применяется, когда требуется создать семейство интерфейсов, реализация которых должна подменяться совместно. Например, при доступе к данным есть стандартный интерфейс, отвечающий за подключение, - IDbConnection, и мой интерфейс, ответственный за преобразование объектной модели запроса в текст запроса, соответствующий стандарту определённой СУБД. Оба этих интерфейса инстанцируются одной фабрикой. В то же время, интерфейс IDbConnection объявляет метод CreateCommand, который возвращает реализацию IDbCommand для соответствующего типа подключения. Это - фабричный метод.

Ответ 2



Лучше показать на примере. class PizzaFactory { def get(): Pizza = new Pizza() } Этот код, является самой простой реализацией фабричного метода. Т.е. есть какой то класс, в котором есть метод, создающий объекты определенного типа. В нашем случае мы создаем пиццу. Теперь расмотрим ситуацию, когда пицца имеет множество видов, и мы хотим получать в разных случаях разные виды. Разные виды пицц наследуются от общего интерфейса Pizza. trait Pizza class ItalianPizza extends Pizza class HawaiiPizza extends Pizza Сделаем для каждого вида, свой фабричный метод, с общим интерфейсом: trait PizzaFactory { abstract def get(): Pizza } class HawaiiFactory extends PizzaFactory { override def get(): Pizza = new HawaiiPizza } class ItalianFactory extends PizzaFactory { override def get(): Pizza = new ItalianPizza } Данная конструкция реализует паттерн - абстрактная фабрика. Как мы видим, фабричный метод является ее частью.

Ответ 3



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

Android - использование Plurals в отношении секунд, минут, часов, дней

#android #строки


Приветствую!
Подскажите как правильнее использовать Plurals в отношении секунд, минут, часов,
дней для вывода времени которое "осталось" и "прошло" 


        секунд
        %1$d секунда
        %1$d секунды
        %1$d секунд
        %1$d секунд



zero, one, two - понятно, но к примеру few - это насколько я понимаю от 2х до 5,
а 5 уже будет не "секунды" и "секунд". И далее - с many, например 101 секунда, 102
секунды,... т.е. действовать должны правила для one, two.
Как учесть эту разницу?
    


Ответы

Ответ 1



Статья zero — строка для нуля, отсутствия чего-либо; в некоторых языках — ещё и для чисел, оканчивающихся нулём; one — строка для чисел, заканчивающихся на единицу; в некоторых языках — только для единицы; two — для чисел, заканчивающихся на двойку, или только для двойки; few— здесь, под словом «несколько», уже не скрывается конкретики, обработка полностью зависит от языковых правил; например, для русского языка это относится к числам, оканчивающимся на 2, 3 и 4 (именно так, несмотря на наличие правила «two»); many — аналогично, «неконкретная» категория, можно понимать её как «нечто побольше few»; в русском языке — от пятёрки и выше; other — всё остальное. Если кратко, то уникальные правила сформулированы для каждого языка в отдельности. В конце статьи есть пример, который должен развеють все недопонимания: нет андроидов %1$d андроид %1$d андроида %1$d андроида %1$d андроидов %1$d андроидов // Выведем данные в формате: 8 = many : 8 андроидов for (int i = 0; i < 30; i++) { String pluralTest = this.getResources().getQuantityString(R.plurals.plurals_1, i, i); String pluralAndroid = this.getResources().getQuantityString(R.plurals.plurals_2, i, i); android.util.Log.i("Plurals", pluralTest + " : " + pluralAndroid); } Результат: 0 = many : 0 андроидов 1 = one : 1 андроид 2 = few : 2 андроида 3 = few : 3 андроида 4 = few : 4 андроида 5 = many : 5 андроидов 6 = many : 6 андроидов 7 = many : 7 андроидов 8 = many : 8 андроидов 9 = many : 9 андроидов 10 = many : 10 андроидов 11 = many : 11 андроидов 12 = many : 12 андроидов 13 = many : 13 андроидов 14 = many : 14 андроидов 15 = many : 15 андроидов 16 = many : 16 андроидов 17 = many : 17 андроидов 18 = many : 18 андроидов 19 = many : 19 андроидов 20 = many : 20 андроидов 21 = one : 21 андроид 22 = few : 22 андроида 23 = few : 23 андроида 24 = few : 24 андроида 25 = many : 25 андроидов 26 = many : 26 андроидов 27 = many : 27 андроидов 28 = many : 28 андроидов 29 = many : 29 андроидов Итого, для русского языка: Для нуля используется zero Для чисел, заканчивающихся на 1(кроме чисел, заканчивающихся на 11) используется one Для чисел, заканчивающихся на 2(кроме чисел, заканчивающихся на 12) используется two (вот только в русском для этих чисел используется правило few) Для чисел, заканчивающихся на 3, 4 (кроме чисел, заканчивающихся на 13, 14) используется few Для всех остальных используется many other используется для других случаев, которых в русском языке нет. Несмотря на это, one и other - обязательный минимум, который должен всегда быть определен. В этой же статье описана проблема с plurals на API < 3.0. Там все plurals работают по правилам английского языка. Там же описано и решение этой проблемы - использовать библиотеку android-i18n-plurals, П. С. Все вышеописанное я взял из вышеперведенной статьи, и если осваивал именно по этой статье. Вопрос остался незакрытым то это означает только одно - плохо осваивал.

Ответ 2



Проблема решилась... забыл переименовать values в values-ru, а то у меня практически все числа попадали в OTHER. Всем спасибо, проблема решена

Ответ 3



Для русского языка one - это все числа, заканчивающиеся на 1, кроме 11. few - заканчивющиеся на 2 - 4, кроме 12 - 14. То есть проблем не будет. Для форматирования относительных дат, чтобы самому не возиться, можно воспользоваться DateUtils#getRelativeTimeSpanString() и другими методами этого класса. Так у вас будет текст не только для одного языка.

Ответ 4



Немного "покапитаню" если в вашей android ОС выбран Английский язык, то приложение будет искать папку values-en, если она не найдена, то будут браться ресурсы из папки values. Аналогично и для Русского языка, если язык ОС выбран русский, то ресурсы сначала будут искаться в values-ru, и если таковой не существует то возьмутся из values. Менять язык ОС - Настройки - Язык и ввод Для полного понимания вопроса, нужно почитать про локализацию приложений. http://developer.alexanderklimov.ru/android/locale.php

Ответ 5



Если на телефоне стоит английский язык - то при использовании plurals значение для кейса 2 будет заменено значением для zero. Это потому что в английском грамматическая форма для 0 и много одинаковая. И если это использовать в приложении где язык русский - то будет 2 Билетов а не 2 Билета

Как получить доступ к private-полям класса извне?

#c++ #language_lawyer


Есть учебное задание, в котором необходимо получить доступ к private-полям класса
извне. struct Cls дана изначально. Я нагуглил что нужно создать копию структуры, но
с public методами, а потом через нее стучаться в изначальную.
Вопрос в том как это реализовать? Как можно вернуть ссылку на private поля?

struct Cls {
  Cls(char c, double d, int i);
  private:
      char c;
      double d;
      int i;
  };



 struct B {
  B(char c, double d, int i);
  public:
      char c1;
      double d1;
      int i1;
 };

// Эта функция должна предоставить доступ к полю c объекта cls.
// Обратите внимание, что возвращается ссылка на char, т. е.
// доступ предоставляется на чтение и запись.
char &get_c(Cls &cls) {

    return ((B*)(&cls))->c1 = 'p';

}

// Эта функция должна предоставить доступ к полю d объекта cls.
// Обратите внимание, что возвращается ссылка на double, т. е.
// доступ предоставляется на чтение и запись.
double &get_d(Cls &cls) {
    /* ... */
}

// Эта функция должна предоставить доступ к полю i объекта cls.
// Обратите внимание, что возвращается ссылка на int, т. е.
// доступ предоставляется на чтение и запись.
int &get_i(Cls &cls) {
    /* ... */
}

int main() {
    Cls cls('h', 2.0, 3);
    char ch = get_c(&cls);
    cout << ch << endl;
}

    


Ответы

Ответ 1



Вы не можете честным и надёжным путём получить доступ к приватным данным. Существуют грубые хаки, наподобие «угадать бинарный лэйаут данных и скастить указатель», которые прямо запрещены стандартом, и дают право компилятору наказать вас в любой момент. Правильный ответ на вопрос, как получить доступ к приватным данным — никак. Ваш преподаватель либо задаёт вопрос с подвохом, либо плохо знает язык, который преподаёт. Конкретно в вашем случае, код (B*)(&cls)->c1 нарушает strict aliasing rule (правило 3.10/10 стандарта). Дополнительное чтение по теме: What is the strict aliasing rule? GotW #76: Uses and Abuses of Access Rights. Окей, исходя из развернувшейся дискуссии в ответе @Vlad from Moscow, вопрос о доступе через указатель на «чужой» тип не так уж очевиден даже из стандарта. Как видите, мы покамест не пришли к общему мнению о том, правомерен ли такой доступ по стандарту. В любом случае, доступ к приватным полям — очень плохой стиль программирования, и даже если так возможно сделать, делать этого не нужно. Обновление: Другие ответы: ([1], [2] и [3]) убедили меня в том, что к приватным полям таки можно получить доступ «законным» — то есть, совместимым со стандартом путём. (Впрочем, с трактовкой стандарта в последнем из них я не вполне согласен, но это лишь показывает, что сам по себе стандарт — достаточно большой и не очень ясно написанный текст.) Тем не менее, любой из приведённых подходов кажется мне грубым хаком, и я бы крайне не рекомендовал пользоваться ими в production-коде. Думаю, будет поучительно, если вы отправите ссылку на это обсуждение вашему преподавателю.

Ответ 2



Формально можно обмануть компилятор следующим образом #include struct Cls { Cls(char c, double d, int i) : c( c ), d( d ), i( i ) {} private: char c; double d; int i; }; struct B { B(char c, double d, int i) : c1( c ), d1( d ), i1( i ) {} public: char c1; double d1; int i1; }; char &get_c( Cls &cls ) { void *p = &cls; B *pb = static_cast( p ); return pb->c1 = 'A';; } int main() { Cls cls('h', 2.0, 3); char ch = get_c( cls) ; std::cout << ch << std::endl; } Вывод программы на консоль: A Это совершенно корректный код, так как обе структуры являются layout-compatible и согласно стандарту C++ (3.9.2 Compound types) ...Pointers to cv-qualified and cv-unqualified versions (3.9.3) of layout-compatible types shall have the same value representation and alignment requirements (3.11). Более подробно: 9.2 Class members: 16 Two standard-layout struct (Clause 9) types are layout-compatible if they have the same number of non-static data members and corresponding non-static data members (in declaration order) have layout-compatible types (3.9). и 9 Classes: 7 A standard-layout class is a class that: — has no non-static data members of type non-standard-layout class (or array of such types) or reference, — has no virtual functions (10.3) and no virtual base classes (10.1), — has the same access control (Clause 11) for all non-static data members, — has no non-standard-layout base classes, — either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and — has no base classes of the same type as the first non-static data member. 8 A standard-layout struct is a standard-layout class defined with the class-key struct or the class-key class. A standard-layout union is a standard-layout class defined with the class-key union Вы также в main могли бы объявить ссылку на объект типа char. Вот более наглядная программа благодаря добавлению дружественного оператора вывода #include struct Cls { Cls(char c, double d, int i) : c( c ), d( d ), i( i ) {} private: char c; double d; int i; friend std::ostream & operator << ( std::ostream &os, const Cls &cls ) { return os << "c = " << cls.c << ", d = " << cls.d << ", i = " << cls.i; } }; struct B { B(char c, double d, int i) : c1( c ), d1( d ), i1( i ) {} public: char c1; double d1; int i1; }; char &get_c( Cls &cls ) { void *p = &cls; B *pb = static_cast( p ); return pb->c1 = 'A';; } int main() { Cls cls('h', 2.0, 3); char &ch = get_c( cls) ; std::cout << ch << std::endl; ch = 'B'; std::cout << cls << std::endl; Ъ Ее вывод на консоль: A c = B, d = 2, i = 3

Ответ 3



Легальный способ - это явная инстанциация шаблона. Согласно [temp.explicit] p12: Правила доступа не применяются к именам использованным при явных инстанциациях. [ Примечание: в частности, шаблонные аргументы и имена использованные при декларации функции (...) могут быть приватными типами или членами, которые обычно не были бы доступны, и шаблон может быть шаблоном функции-члена класса, которая обычно не была бы доступна. — конец примечания ] Это можно использовать следующим способом: Допустим у нас есть класс class Cls { public: Cls() : i(42) {} virtual ~Cls() {} private: int i; }; Тип указателя на член класса i выглядит как: typedef int Cls::* mem_ptr_t; Напишем шаблонный класс, принимающий шаблонный параметр mem_ptr_t и сохраняюший его в глобальную переменную g_mem_ptr: mem_ptr_t g_mem_ptr; template class Helper { static bool b; }; template bool Helper

::b = (g_mem_ptr = P, false); // оператор "запятая" ^ Теперь мы можем инстанциировать Helper<&Cls::i>, и в g_mem_ptr окажется указатель на нужный нам член класса: template class Helper<&Cls::i>; int main() { Cls obj; int& i = obj.*g_mem_ptr; std::cout << i << '\n'; } >>> Код полностью <<< "Библиотечная" версия, для любых классов и членов класса выглядит примерно так: http://coliru.stacked-crooked.com/a/4d4f64adc7a36ab9

Ответ 4



http://ideone.com/gTyt2Q #include #include struct cls { public: cls(char c, double d, int i) : c(c), d(d), i(i) {} private: char c; double d; int i; }; struct copy { public: copy(char c, double d, int i); public: char c; double d; int i; }; int main(void) { cls x('1', 2.5, 3); printf ( "%c %f %d\n", *(char*)((void*)&x + offsetof(copy, c)), *(double*)((void*)&x + offsetof(copy, d)), *(int*)((void*)&x + offsetof(copy, i)) ); return 0; } Вроде бы в комментариях пришли к выводу, что этот код не содержит UB, поскольку: Структуры с одинаковым набором и последовательностью полей имеют одинаковое внутреннее представление. Приведение указателя к другому типу не является UB до тех пор, пока не делается его разыменование. Кроме того, в данном коде приведение делается только к void*. Добавление смещения к адресу структуры даёт указатель на её поле. Указатель на поле приводится к корректному типу, поэтому его разыменование не приводит к UB.

Ответ 5



А можно и без функций для доступа (и для разнообразия, а то что-то все про union забыли). int main (int ac, char *av[]) { union u { struct Cls hidden; struct B B; } *up; Cls cls('h', 2.0, 3); B b('A', 3.14, 10); up = (union u *)&cls; cout << up->B.c1 << ' ' << up->B.d1 << ' ' << up->B.i1 << '\n'; up->B = b; cout << up->B.c1 << ' ' << up->B.d1 << ' ' << up->B.i1 << '\n'; } Результат avp@avp-ubu1:hashcode$ g++ c.cpp -std=c++11 avp@avp-ubu1:hashcode$ ./a.out h 2 3 A 3.14 10 avp@avp-ubu1:hashcode$ Если же использовать -std=gnu++11, то union можно сделать безымянным, а приведение типа up = (typeof(up))&cls; вот так.

Ответ 6



Вам нужно применить паттерн "Паблик Морозов" #define private public #define protected public #include "your class header.h" #undef private #undef protected После такого подключения все закрытые поля класса, объявленного в Yourclass header.h станут пабликами.

Ответ 7



class A { #ifdef BOOST_TEST_MODULE public: #endif

Вопрос о heap memory в Java

#java


Возник вопрос о heap memory. Так вот обратите внимание на жирный курсив. в 1-м варианте
все нормально работает. Но вот во втором выскакивает 


  OutOfMemoryError: Java heap space. 


Кто подскажет почему?


public class idea_test {
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader("S:\\idea test\\src\\file.txt")); 
        ArrayList strings = new ArrayList();  

        (1)          
        String s;                                           
        while ((s = reader.readLine()) != null){
            strings.add(s);                                                     
        }

        (2)
        String s = reader.readLine();                                           
        while (s != null){
            strings.add(s);                                                     
        }

        reader.close();                                                         
        String[] strings1 = strings.toArray(new String[strings.size()]);        
        Arrays.sort(strings1);                                                  
        for (String s1 : strings1) {
            System.out.println(s1);
        }
    }
}

    


Ответы

Ответ 1



Ну так элементарно. В первом случае мы крутимся в цикле и при каждой итерации вызываем reader.readLine() после чего проверяем s на null, если все строки файла были прочитаны((s = reader.readLine()) != null == false), то благополучно вываливаемся из цикла. Во втором же случае у нас получается бесконечный цикл, так как мы один раз вызвали reader.readLine() а далее бесконечно крутимся в цикле (так как s != null - истинно всегда, ведь мы же не меняем s), добавляя в ArrayList одни и те же значения, что и приводит к OutOfMemoryError

private static и private final static - зачем?

#java


В каких случаях следует помечать переменные таким образом? Какой толк от static,
если он помечен как private?
    


Ответы

Ответ 1



Посмотрите данные по шаблону проектирования singleton. private static гарантирует единственность экземпляра объекта с такими свойствами в потоке, где задействован класс. private static final гарантирует, что этот экземпляр не подменится на что-то другое. Удобно при работе с базами данных или каким-то ресурсом, не склонным к разделению.

Ответ 2



Какой толк от static, если он помечен как private? Необходимо, если переменную нужно использовать в статических методах public class CarFactoryFacade { private static CarFactory audiFactory = new AudiCarFactory(); private CarFactory bmwFactory = new BMWCarFactory(); public static Car createAudi() { return audiFactory.createCar(); } public static Car createBMW() { return bmwFactory.createCar(); <-- ошибка } private final static - зачем? Final нужно использовать, если ссылка будет инициализироваться один раз и не должна быть заменена. В большинстве случаев static переменные именно так и используются. Если static переменная изменяется в ходе программы, скорее всего есть какие то проблемы с дизайном (static - отсутствие экземпляра объекта, в каком то смысле отсутствие состояния, изменение ссылки - смена состояние -> противоречие).

Ответ 3



Модификаторы доступа static final следует применять, когда есть необходимость явно указать на то, что переменную не следует или запрещено изменять, то есть модификаторы static final превращают переменную в константу. В свою очередь переменные помеченные модификатором static являются обычными переменными с тем лишь различием, что их экземпляр (в единственном числе) хранится не с экземпляром каждого создаваемого объекта (области памяти где хранятся переменные экземпляра), а в объекте который описывает ваш класс при этом на каждой JVM такой объект существует в единственном экземпляре. С переменными объявленными как static можно делать все то же что и с обычными переменными при этом для доступа к таким переменным ненужно (но можно получить доступ и через переменную экземпляра) создавать экземпляр класса (конечно если переменная имеет модификатор доступа public), например, создадим класс содержащий статическую переменную: public class MyClass{ public static int classVariable = 10; } Получение подступа к статической переменной: MyClass.classVariable; Присваиваем новое значение статической переменной: MyClass.classVariable = 100; Такие переменные следует применять, когда есть необходимость иметь одну переменную на все экземпляры классов или если необходимо использовать переменную в статическом методе (переменные экземпляра в таком методе недоступны так как экземпляров класса может вообще не существовать на момент вызова статического метода). При использовании модификатора private свойства переменной и «константы» не изменяются, изменяется лишь доступность переменной/константы.

Почему INNER JOIN в SQL получило такое название?

#sql


Понятно что слово INNER переводится как ВНУТРЕННИЙ. Не понятно почему именно внутреннее
соединение а не красное соединение или зеленое?
    


Ответы

Ответ 1



Диаграммы Эйлера-Венна Вам в помощь:

Как создать эффект пульсации при клике - `Material Design`

#javascript #html #jquery #css #css3


Я новичок в CSS-анимации, и  стараюсь в течение последних часов, чтобы  анимация
заработала. Пытаюсь понять код Material Design, но пока  не могу заставить его работать.  

Я говорю об этом эффекте: https://angular.io/ (эффект меню). В принципе, это анимация
при клике, которая распространяется по кругу от курсора мыши.   

Кажется, это сводится к этим двум строкам:  

transition: box-shadow .4s cubic-bezier(.25,.8,.25,1),background-color .4s cubic-bezier(.25,.8,.25,1),-webkit-transform
.4s cubic-bezier(.25,.8,.25,1);
transition: box-shadow .4s cubic-bezier(.25,.8,.25,1),background-color .4s cubic-bezier(.25,.8,.25,1),transform
.4s cubic-bezier(.25,.8,.25,1);   


PS: Может быть, есть какой-то код jQuery, который реализует эту анимацию.    

Перевод ответа: How to create Ripple effect on Click - Material Design @topleft
    


Ответы

Ответ 1



Вариант с CSS-переменными, которые используются для раздельного использования свойства transform. Разделять это свойство понадобилось для того, чтобы правильно перемещать элемент (translate3d) и независимо от перемещения масштабировать (scale). Через JS так можно очень удобно управлять этими параметрами. С точки зрения производительности это достаточно хорошая анимация такого эффекта, поскольку не делаются вставки и удаления узлов в DOM и вся работа происходит исключительно со свойствами transform и opacity, которые не влияют на композитный слой, а значит не вызывают множество перерисовок страницы. let span = document.querySelector('button span'); document.querySelector('button').addEventListener('click', function(e) { span.style.setProperty('--x', e.clientX - this.getBoundingClientRect().left - span.offsetWidth/2 + 'px'); span.style.setProperty('--y', e.clientY - this.getBoundingClientRect().top - span.offsetHeight/2 + 'px'); let scaleCount = 0, opacityCount = 1; const animationTime = 500; let scaleUp = setInterval(function() { scaleCount += 0.25; span.style.setProperty('--scale', scaleCount); opacityCount -= 0.05; span.style.opacity = opacityCount; }, animationTime / 20); setTimeout(function() { clearInterval(scaleUp); span.style.setProperty('--scale', 0); }, animationTime); }); body { --x: 0px; --y: 0px; --scale: 0; } button { padding: 10px 20px; position: relative; overflow: hidden; border: 0; border-radius: 3px; background: linear-gradient(#c4e2fa, #c4effa); outline: 0; font: bold 17px arial; text-shadow: 0 0 3px rgba(0,0,0,0.3); color: #FFF; } button:hover { background: linear-gradient(#c4e2fa, #c4e8fa); } span { position: absolute; width: 30px; height: 30px; border-radius: 50%; background-color: rgba(0, 0, 0, 0.3); top: 0; left: 0; transform: translate3d(var(--x), var(--y), 0) scale(var(--scale)); }

Ответ 2



Эффект пульсации в Material Design с использованием jQuery и CSS3 jsBin demo Чтобы создать UI Ripple effect, вам необходимо: Добавить к любому элементу oveflow:hidden, чтобы ограничить круг пульсаций (так как вы не хотите изменять ваш исходный элемент и поэтому с помощью overflow не увидите, что эффект пульсации выходит за пределы желаемого контейнера) Добавить к контейнеру c overflow просвечивающий радиальный элемент ripple wave Взять координаты щелчка мышки, и с помощью CSS3 оживить масштабирование и непрозрачность ripple element Прослушайте событие - анимация и уничтожьте пульсацию. Основной код: В основном добавьте data-ripple (по умолчанию - белая рябь) или data-ripple = "# 000" для нужного элемента: EDIT
Lorem ipsum
CSS: /* MAD-RIPPLE EFFECT */ .ripple{ position: absolute; top:0; left:0; bottom:0; right:0; overflow: hidden; -webkit-transform: translateZ(0); /* to contain zoomed ripple */ transform: translateZ(0); border-radius: inherit; /* inherit from parent (rounded buttons etc) */ pointer-events: none; /* allow user interaction */ animation: ripple-shadow 0.4s forwards; -webkit-animation: ripple-shadow 0.4s forwards; } .rippleWave{ backface-visibility: hidden; position: absolute; border-radius: 50%; transform: scale(0.7); -webkit-transform: scale(0.7); background: rgba(255,255,255, 1); opacity: 0.45; animation: ripple 2s forwards; -webkit-animation: ripple 2s forwards; } @keyframes ripple-shadow { 0% {box-shadow: 0 0 0 rgba(0,0,0,0.0);} 20% {box-shadow: 0 4px 16px rgba(0,0,0,0.3);} 100% {box-shadow: 0 0 0 rgba(0,0,0,0.0);} } @-webkit-keyframes ripple-shadow { 0% {box-shadow: 0 0 0 rgba(0,0,0,0.0);} 20% {box-shadow: 0 4px 16px rgba(0,0,0,0.3);} 100% {box-shadow: 0 0 0 rgba(0,0,0,0.0);} } @keyframes ripple { to {transform: scale(24); opacity:0;} } @-webkit-keyframes ripple { to {-webkit-transform: scale(24); opacity:0;} } jQuery jQuery(function($) { // MAD-RIPPLE // (jQ+CSS) $(document).on("mousedown", "[data-ripple]", function(e) { var $self = $(this); if($self.is(".btn-disabled")) { return; } if($self.closest("[data-ripple]")) { e.stopPropagation(); } var initPos = $self.css("position"), offs = $self.offset(), x = e.pageX - offs.left, y = e.pageY - offs.top, dia = Math.min(this.offsetHeight, this.offsetWidth, 100), // start diameter $ripple = $('
', {class : "ripple",appendTo : $self }); if(!initPos || initPos==="static") { $self.css({position:"relative"}); } $('
', { class : "rippleWave", css : { background: $self.data("ripple"), width: dia, height: dia, left: x - (dia/2), top: y - (dia/2), }, appendTo : $ripple, one : { animationend : function(){ $ripple.remove(); } } }); }); }); Вот полнофункциональная демонстрация: jQuery(function($) { // MAD-RIPPLE // (jQ+CSS) $(document).on("mousedown", "[data-ripple]", function(e) { var $self = $(this); if($self.is(".btn-disabled")) { return; } if($self.closest("[data-ripple]")) { e.stopPropagation(); } var initPos = $self.css("position"), offs = $self.offset(), x = e.pageX - offs.left, y = e.pageY - offs.top, dia = Math.min(this.offsetHeight, this.offsetWidth, 100), // start diameter $ripple = $('
', {class : "ripple",appendTo : $self }); if(!initPos || initPos==="static") { $self.css({position:"relative"}); } $('
', { class : "rippleWave", css : { background: $self.data("ripple"), width: dia, height: dia, left: x - (dia/2), top: y - (dia/2), }, appendTo : $ripple, one : { animationend : function(){ $ripple.remove(); } } }); }); }); *{box-sizing:border-box; -webkit-box-sizing:border-box;} html, body{height:100%; margin:0;} body{background:#f5f5f5; font: 14px/20px Roboto, sans-serif;} h1, h2{font-weight: 300;} /* MAD-RIPPLE EFFECT */ .ripple{ position: absolute; top:0; left:0; bottom:0; right:0; overflow: hidden; -webkit-transform: translateZ(0); /* to contain zoomed ripple */ transform: translateZ(0); border-radius: inherit; /* inherit from parent (rounded buttons etc) */ pointer-events: none; /* allow user interaction */ animation: ripple-shadow 0.4s forwards; -webkit-animation: ripple-shadow 0.4s forwards; } .rippleWave{ backface-visibility: hidden; position: absolute; border-radius: 50%; transform: scale(0.7); -webkit-transform: scale(0.7); background: rgba(255,255,255, 1); opacity: 0.45; animation: ripple 2s forwards; -webkit-animation: ripple 2s forwards; } @keyframes ripple-shadow { 0% {box-shadow: 0 0 0 rgba(0,0,0,0.0);} 20% {box-shadow: 0 4px 16px rgba(0,0,0,0.3);} 100% {box-shadow: 0 0 0 rgba(0,0,0,0.0);} } @-webkit-keyframes ripple-shadow { 0% {box-shadow: 0 0 0 rgba(0,0,0,0.0);} 20% {box-shadow: 0 4px 16px rgba(0,0,0,0.3);} 100% {box-shadow: 0 0 0 rgba(0,0,0,0.0);} } @keyframes ripple { to {transform: scale(24); opacity:0;} } @-webkit-keyframes ripple { to {-webkit-transform: scale(24); opacity:0;} } /* MAD-BUTTONS (demo) */ [class*=mad-button-]{ display:inline-block; text-align:center; position: relative; margin: 0; white-space: nowrap; vertical-align: middle; font-family: "Roboto", sans-serif; font-size: 14px; font-weight: 500; text-transform: uppercase; text-decoration: none; border: 0; outline: 0; background: none; transition: 0.3s; cursor: pointer; color: rgba(0,0,0, 0.82); } [class*=mad-button-] i.material-icons{ vertical-align:middle; padding:0; } .mad-button-raised{ height: 36px; padding: 0px 16px; line-height: 36px; border-radius: 2px; box-shadow: /*amb*/ 0 0 2px rgba(0,0,0,0.15), /*key*/ 0 1px 3px rgba(0,0,0,0.25); }.mad-button-raised:hover{ box-shadow: /*amb*/ 0 0 2px rgba(0,0,0,0.13), /*key*/ 0 2px 4px rgba(0,0,0,0.2); } .mad-button-action{ width: 56px; height:56px; padding: 16px 0; border-radius: 32px; box-shadow: /*amb*/ 0 0 2px rgba(0,0,0,0.13), /*key*/ 0 5px 7px rgba(0,0,0,0.2); }.mad-button-action:hover{ box-shadow: /*amb*/ 0 0 2px rgba(0,0,0,0.11), /*key*/ 0 6px 9px rgba(0,0,0,0.18); } [class*=mad-button-].mad-ico-left i.material-icons{ margin: 0 8px 0 -4px; } [class*=mad-button-].mad-ico-right i.material-icons{ margin: 0 -4px 0 8px; } /* MAD-COLORS */ .bg-primary-darker{background:#1976D2; color:#fff;} .bg-primary{ background:#2196F3; color:#fff; } .bg-primary.lighter{ background: #BBDEFB; color: rgba(0,0,0,0.82);} .bg-accented{ background:#FF4081; color:#fff; } /* MAD-CELL */ .cell{padding: 8px 16px; overflow:auto;}
search

Click to Ripple

data-ripple

data-ripple="rgba(0,0,0, 0.4)"

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore....

Editedit

Перевод ответа: How to create Ripple effect on Click - Material Design @Roko C. Buljan

Ответ 3



На чистом js + babel - javascript - class ImpulseStyleFactory { static ANIMATION_DEFAULT_DURATION = 1; static ANIMATION_DEFAULT_SIZE = 300; static ANIMATION_RATIO = ImpulseStyleFactory.ANIMATION_DEFAULT_DURATION / ImpulseStyleFactory.ANIMATION_DEFAULT_SIZE; static circleImpulseStyle( x, y, size, color = `#fff`, duration = 1 ){ return { width: `${ size }px`, height: `${ size }px`, background: color, borderRadius: `50%`, display: `inline-block`, pointerEvents: `none`, position: `absolute`, top: `${ y - size / 2 }px`, left: `${ x - size / 2 }px`, animation: `impulse ${ duration }s`, }; } } class Impulse { static service = new Impulse(); static install( container ) { Impulse.service.containerRegister( container ); } static destroy( container ){ Impulse.service.containerUnregister( container ); } static applyToElement( {x, y}, container ){ Impulse.service.createImpulse( x, y, container ); } constructor(){ this.impulse_clickHandler = this.impulse_clickHandler.bind(this); this.impulse_animationEndHandler = this.impulse_animationEndHandler.bind(this); this.actives = new Map(); } containerRegister( container ){ container.addEventListener('click', this.impulse_clickHandler); } containerUnregister( container ){ container.removeEventListener('click', this.impulse_clickHandler); } createImpulse( x, y, container ){ let { clientWidth, clientHeight } = container; let impulse = document.createElement('div'); impulse.addEventListener('animationend', this.impulse_animationEndHandler); let size = Math.max( clientWidth, clientHeight ) * 2; let color = container.dataset.color; Object.assign(impulse.style, ImpulseStyleFactory.circleImpulseStyle( x, y, size, color )); if( this.actives.has( container ) ){ this.actives.get( container ) .add( impulse ); }else{ this.actives.set( container, new Set( [ impulse ] ) ); } container.dataset.active = true; container.appendChild( impulse ); } impulse_clickHandler({ layerX, layerY, currentTarget: container }){ this.createImpulse( layerX, layerY, container ); } impulse_animationEndHandler( {currentTarget: impulse} ){ let { parentNode: container } = impulse; this.actives.get( container ) .delete( impulse ); if( ! this.actives.get( container ).size ){ this.actives.delete( container ); container.dataset.active = false; } container.removeChild(impulse); } } css - @keyframes impulse { from { opacity: .3; transform: scale(0); } to { opacity: 0; transform: scale(1); } } использовать так - html -
javascript - let impulses = document.querySelectorAll('.impulse'); let impulseAll = Array.from( impulses ); impulseAll.forEach( Impulse.install ); Живой пример с Impulse.install ( импульс создается в координатах клика, навешивается слушатель события click ) - class ImpulseStyleFactory { static ANIMATION_DEFAULT_DURATION = 1; static ANIMATION_DEFAULT_SIZE = 300; static ANIMATION_RATIO = ImpulseStyleFactory.ANIMATION_DEFAULT_DURATION / ImpulseStyleFactory.ANIMATION_DEFAULT_SIZE; static circleImpulseStyle( x, y, size, color = `#fff`, duration = 1 ){ return { width: `${ size }px`, height: `${ size }px`, background: color, borderRadius: `50%`, display: `inline-block`, pointerEvents: `none`, position: `absolute`, top: `${ y - size / 2 }px`, left: `${ x - size / 2 }px`, animation: `impulse ${ duration }s`, }; } } class Impulse { static service = new Impulse(); static install( container ) { Impulse.service.containerRegister( container ); } static destroy( container ){ Impulse.service.containerUnregister( container ); } static applyToElement( {x, y}, container ){ Impulse.service.createImpulse( x, y, container ); } constructor(){ this.impulse_clickHandler = this.impulse_clickHandler.bind(this); this.impulse_animationEndHandler = this.impulse_animationEndHandler.bind(this); this.actives = new Map(); } containerRegister( container ){ container.addEventListener('click', this.impulse_clickHandler); } containerUnregister( container ){ container.removeEventListener('click', this.impulse_clickHandler); } createImpulse( x, y, container ){ let { clientWidth, clientHeight } = container; let impulse = document.createElement('div'); impulse.addEventListener('animationend', this.impulse_animationEndHandler); let size = Math.max( clientWidth, clientHeight ) * 2; let color = container.dataset.color; Object.assign(impulse.style, ImpulseStyleFactory.circleImpulseStyle( x, y, size, color )); if( this.actives.has( container ) ){ this.actives.get( container ) .add( impulse ); }else{ this.actives.set( container, new Set( [ impulse ] ) ); } container.dataset.active = true; container.appendChild( impulse ); } impulse_clickHandler({ layerX, layerY, currentTarget: container }){ this.createImpulse( layerX, layerY, container ); } impulse_animationEndHandler( {currentTarget: impulse} ){ let { parentNode: container } = impulse; this.actives.get( container ) .delete( impulse ); if( ! this.actives.get( container ).size ){ this.actives.delete( container ); container.dataset.active = false; } container.removeChild(impulse); } } let impulses = document.querySelectorAll('.impulse'); let impulseAll = Array.from( impulses ); impulseAll.forEach( Impulse.install ); @import "https://cdnjs.cloudflare.com/ajax/libs/normalize/6.0.0/normalize.min.css"; /*@import url('https://fonts.googleapis.com/css?family=Roboto+Mono');*/ * { box-sizing: border-box; } html { font-family: 'Roboto Mono', monospace; } body { width: 100%; height: 100%; margin: 0; position: absolute; } main { width: 100%; height: 100%; overflow: hidden; position: relative; } .container { position: absolute; top: 0; left: 0; } .centred { display: flex; justify-content: center; align-items: center; } .shadow-xs { box-shadow: rgba(0, 0, 0, 0.117647) 0px 1px 6px, rgba(0, 0, 0, 0.117647) 0px 1px 4px; } .sample-impulse { transition: all .5s; overflow: hidden; position: relative; } .sample-impulse[data-active="true"] { box-shadow: rgba(0, 0, 0, 0.156863) 0px 3px 10px, rgba(0, 0, 0, 0.227451) 0px 3px 10px; } .panel { width: 300px; height: 100px; background: #fff; } .panel__hidden-label { color: #fff; font-size: 2rem; font-weight: bold; pointer-events: none; z-index: 1; position: absolute; } .panel__default-label { pointer-events: none; z-index: 2; position: absolute; } .sample-impulse[data-active="true"] .panel__default-label { display: none; } @keyframes impulse { from { opacity: .3; transform: scale(0); } to { opacity: 0; transform: scale(1); } }
StackOverflow click me
Живой пример с Impulse.applyToElement ( координаты импульса задаются вручную, слушатель события click не навешивается ) - class ImpulseStyleFactory { static ANIMATION_DEFAULT_DURATION = 1; static ANIMATION_DEFAULT_SIZE = 300; static ANIMATION_RATIO = ImpulseStyleFactory.ANIMATION_DEFAULT_DURATION / ImpulseStyleFactory.ANIMATION_DEFAULT_SIZE; static circleImpulseStyle( x, y, size, color = `#fff`, duration = 1 ){ return { width: `${ size }px`, height: `${ size }px`, background: color, borderRadius: `50%`, display: `inline-block`, pointerEvents: `none`, position: `absolute`, top: `${ y - size / 2 }px`, left: `${ x - size / 2 }px`, animation: `impulse ${ duration }s`, }; } } class Impulse { static service = new Impulse(); static install( container ) { Impulse.service.containerRegister( container ); } static destroy( container ){ Impulse.service.containerUnregister( container ); } static applyToElement( {x, y}, container ){ Impulse.service.createImpulse( x, y, container ); } constructor(){ this.impulse_clickHandler = this.impulse_clickHandler.bind(this); this.impulse_animationEndHandler = this.impulse_animationEndHandler.bind(this); this.actives = new Map(); } containerRegister( container ){ container.addEventListener('click', this.impulse_clickHandler); } containerUnregister( container ){ container.removeEventListener('click', this.impulse_clickHandler); } createImpulse( x, y, container ){ let { clientWidth, clientHeight } = container; let impulse = document.createElement('div'); impulse.addEventListener('animationend', this.impulse_animationEndHandler); let size = Math.max( clientWidth, clientHeight ) * 2; let color = container.dataset.color; Object.assign(impulse.style, ImpulseStyleFactory.circleImpulseStyle( x, y, size, color )); if( this.actives.has( container ) ){ this.actives.get( container ) .add( impulse ); }else{ this.actives.set( container, new Set( [ impulse ] ) ); } container.dataset.active = true; container.appendChild( impulse ); } impulse_clickHandler({ layerX, layerY, currentTarget: container }){ this.createImpulse( layerX, layerY, container ); } impulse_animationEndHandler( {currentTarget: impulse} ){ let { parentNode: container } = impulse; this.actives.get( container ) .delete( impulse ); if( ! this.actives.get( container ).size ){ this.actives.delete( container ); container.dataset.active = false; } container.removeChild(impulse); } } const generateRandomPointByRectdAll = ( { width, height }, length = 1 ) => { let result = []; while( length-- ){ result.push( { x: Math.round( Math.random() * width ), y: Math.round( Math.random() * height ) } ); } return result; }; const delayTask = ( task, delay ) => new Promise( ( resolve, reject ) => { let timeoutID = setTimeout( () => task( ), delay ) } ); document.addEventListener( 'click', () => { const MAX_IMPULSE_DELAY_TIME = 5000; let container = document.querySelector('.custom-impulse'); let pointAll = generateRandomPointByRectdAll( { width: container.clientWidth, height: container.clientHeight }, 5 ); let taskAll = pointAll.map( point => () => Impulse.applyToElement( point, container ) ); let delayTaskAll = taskAll.map( task => delayTask( task, Math.round( Math.random() * MAX_IMPULSE_DELAY_TIME ) ) ); } ); @import "https://cdnjs.cloudflare.com/ajax/libs/normalize/6.0.0/normalize.min.css"; /*@import url('https://fonts.googleapis.com/css?family=Roboto+Mono');*/ * { box-sizing: border-box; } html { font-family: 'Roboto Mono', monospace; } body { width: 100%; height: 100%; margin: 0; position: absolute; } main { width: 100%; height: 100%; overflow: hidden; position: relative; } .container-fill { width: 100%; height: 100%; } .container { position: absolute; top: 0; left: 0; } .centred { display: flex; justify-content: center; align-items: center; } .custom-impulse { will-change: transform, opasity; position: absolute; } @keyframes impulse { from { opacity: .3; transform: scale(0); } to { opacity: 0; transform: scale(1); } }
click me


Ответ 4



Я использовал этот код раньше в нескольких моих проектах. Используя jQuery, мы можем поместить эффект на него не просто статически, но и затем добавить на элемент span onclick. Я добавил комментарии, чтобы было проще понять код. Demo Here jQuery $("div").click(function (e) { // Remove any old one $(".ripple").remove(); // Setup var posX = $(this).offset().left, posY = $(this).offset().top, buttonWidth = $(this).width(), buttonHeight = $(this).height(); // Add the element $(this).prepend(""); // Make it round! if(buttonWidth >= buttonHeight) { buttonHeight = buttonWidth; } else { buttonWidth = buttonHeight; } // Get the center of the element var x = e.pageX - posX - buttonWidth / 2; var y = e.pageY - posY - buttonHeight / 2; // Add the ripples CSS and start the animation $(".ripple").css({ width: buttonWidth, height: buttonHeight, top: y + 'px', left: x + 'px' }).addClass("rippleEffect"); }); CSS .ripple { width: 0; height: 0; border-radius: 50%; background: rgba(255, 255, 255, 0.4); transform: scale(0); position: absolute; opacity: 1; } .rippleEffect { animation: rippleDrop .6s linear; } @keyframes rippleDrop { 100% { transform: scale(2); opacity: 0; } } Перевод ответа: How to create Ripple effect on Click - Material Design @Ruddy

Ответ 5



Такая анимация может быть достигнута с помощью box-shadows. Размещение начала окружности под курсором мышки, при щелчке мышью потребуется JS. li{ font-size:2em; background:rgba(51, 51, 254, 0.8); list-style-type:none; display:inline-block; line-height:2em; width:6em; text-align:center; color:#fff; position:relative; overflow:hidden; } a{color:#fff;} a:after{ content:''; position:absolute; border-radius:50%; height:10em; width:10em; top: -4em; left:-2em; box-shadow: inset 0 0 0 5em rgba(255,255,255,0.2); transition: box-shadow 0.8s; } a:focus:after{ box-shadow: inset 0 0 0 0em rgba(255,255,255,0.2); } Перевод ответа: How to create Ripple effect on Click - Material Design @web-tiki

Как узнать доступен ли файл для открытия и записи?

#c_sharp


Есть папка в сети, в которой периодически создаются файлы. Есть необходимость копировать
данные файлы в другой каталог. Нужно проверять, доступен ли файл для копирования, т.е.
не дописывается ли он. Есть ли возможность проверить доступен ли файл для записи? Для
примера, я открываю файл через Adobe Reader, данный файл не должен копироваться. Мне
нужен ответ скорее на вопрос "Как узнать, открыт ли файл другой программой для изменения?"
    


Ответы

Ответ 1



Для этого можно использовать библиотеку со странным названием Restart Manager. Пример получения списка процессов, занявших файл (https://code.msdn.microsoft.com/windowsapps/How-to-know-the-process-704839f4): using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Text; using System.Windows.Forms; using System.Diagnostics; using System.Runtime.InteropServices; namespace RMTest { public partial class Form1 : Form { [DllImport("Rstrtmgr.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)] public static extern UInt32 RmStartSession(out UInt32 pSessionHandle, UInt32 dwSessionFlags, string strSessionKey); [DllImport("Rstrtmgr.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)] public static extern UInt32 RmRegisterResources(UInt32 dwSessionHandle, UInt32 nFiles,string[] rgsFilenames,UInt32 nApplications, UInt32 rgApplications,UInt32 nServices,UInt32 rgsServiceNames); [DllImport("Rstrtmgr.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)] public static extern UInt32 RmGetList(UInt32 dwSessionHandle, out UInt32 pnProcInfoNeeded, ref UInt32 pnProcInfo,[In, Out] RM_PROCESS_INFO[] rgAffectedApps,ref UInt32 lpdwRebootReasons); [DllImport("Rstrtmgr.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)] public static extern UInt32 RmEndSession(UInt32 dwSessionHandle); const UInt32 RmRebootReasonNone = 0x0; /*Получение списка процессов, имеющих блокировку на файле*/ static public List GetLockProcesses(string path) { uint handle; string key = Guid.NewGuid().ToString(); List processes = new List(); uint res = RmStartSession(out handle, (uint)0, key); if (res != 0) { throw new Exception("Could not begin restart session. " + "Unable to determine file locker."); } try { const int ERROR_MORE_DATA = 234; uint pnProcInfoNeeded = 0, pnProcInfo = 0, lpdwRebootReasons = RmRebootReasonNone; string[] resources = new string[] { path }; res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, 0, 0, 0); if (res != 0) { throw new Exception("Could not register resource."); } res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons); if (res == ERROR_MORE_DATA) { // Create an array to store the process results. RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded]; pnProcInfo = pnProcInfoNeeded; // Get the list. res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons); if (res == 0) { processes = new List((int)pnProcInfo); // Enumerate all of the results and add them to the // list to be returned. for (int i = 0; i < pnProcInfo; i++) { try { processes.Add(Process.GetProcessById(processInfo[i]. Process.dwProcessId)); } // Catch the error in case the process is no longer running. catch (ArgumentException) { } } } else { throw new Exception("Could not list processes locking resource"); } } else if (res != 0) { throw new Exception("Could not list processes locking resource." + "Failed to get size of result."); } } finally { RmEndSession(handle); } return processes; } public Form1() { InitializeComponent(); string f = "C:\\some_file.pdf"; var p = GetLockProcesses(f); textBox1.Text = ""; foreach (Process proc in p) { textBox1.Text += proc.ProcessName + Environment.NewLine; } ; } } [StructLayout(LayoutKind.Sequential)] public struct RM_UNIQUE_PROCESS { // The product identifier (PID). public int dwProcessId; // The creation time of the process. public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime; } /// /// Describes an application that is to be registered with the Restart Manager. /// [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct RM_PROCESS_INFO { const int CCH_RM_MAX_APP_NAME = 255; const int CCH_RM_MAX_SVC_NAME = 63; // Contains an RM_UNIQUE_PROCESS structure that uniquely identifies the // application by its PID and the time the process began. public RM_UNIQUE_PROCESS Process; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)] // If the process is a service, this parameter returns the // long name for the service. public string strAppName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)] // If the process is a service, this is the short name for the service. public string strServiceShortName; // Contains an RM_APP_TYPE enumeration value. public RM_APP_TYPE ApplicationType; // Contains a bit mask that describes the current status of the application. public uint AppStatus; // Contains the Terminal Services session ID of the process. public uint TSSessionId; // TRUE if the application can be restarted by the // Restart Manager; otherwise, FALSE. [MarshalAs(UnmanagedType.Bool)] public bool bRestartable; } /// /// Specifies the type of application that is described by /// the RM_PROCESS_INFO structure. /// public enum RM_APP_TYPE { // The application cannot be classified as any other type. RmUnknownApp = 0, // A Windows application run as a stand-alone process that // displays a top-level window. RmMainWindow = 1, // A Windows application that does not run as a stand-alone // process and does not display a top-level window. RmOtherWindow = 2, // The application is a Windows service. RmService = 3, // The application is Windows Explorer. RmExplorer = 4, // The application is a stand-alone console application. RmConsole = 5, // A system restart is required to complete the installation because // a process cannot be shut down. RmCritical = 1000 } } Работает на ОС начиная с Windows Vista.

Ответ 2



Наиболее трезвый, на мой взгляд, способ понять занят ли файл другим процессом - это попытаться скопировать его и получить System.IO.IOException в случае ошибки ввода-вывода, которая как раз таки и будет возникать при отсутствии к нему доступа. Попытки реализовать метод что бы проверить блокирован файл или нет особого результата не дадут. Поскольку никто не гарантирует, что в промежутке между вызовом метода проверки на блокировку и копированием файла ни какой другой процесс его уже не занял.

Ответ 3



Вот готовый проект. Все делается через системный openfiles.exe который находится в c:\Windows\System32 Он поддерживает множество операций таких как закрытие файла, запросы и т.д.

Ответ 4



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

При первом заходе на сайт, который крутится на IIS, сайт очень долго открывается

#iis #windows_server_2012


При первом заходе на сайт, который крутится на IIS 8 на Windows Server 2012 r2, сайт
очень долго открывается. потом работает нормально, через некоторое время захожу - снова
долго открывается. С чего начать искать в чем проблема, или может кто-то подскажет
решение?.. Элементарные вещи, как ресурсы сервера, стабильность подключение по сети
проверил, все норм...
    


Ответы

Ответ 1



По умолчанию IIS останавливает неактивные сайты для сохранения ресурсов сервера, и на компьютерах разработчиков или на серверах по типу "все в одном" это - нормальное поведение. Если у вас выделенный сервер специально для сайтов - можно настроить чтобы сайт был доступен всегда. Для этого надо зайти в дополнительные параметры пула приложений и поменять следующие настройки (названия настроек привожу для русского IIS для Windows 8.1, другие версии могут немного отличаться - но принцип тот же): Режим запуска (startMode): AlwaysRunning Тайм-аут простоя (idleTimeout): 0 Скриншот: https://i.stack.imgur.com/okN53.png Если у вас статический сайт - этого достаточно. Но статический сайт и без этого тормозить не должен, поэтому я предполагаю что у вас веб-приложение. Чтобы веб-приложение быстро работало, оно должно запуститься и загрузить свои ресурсы ("прогреть кеши"). Это тоже можно сделать автоматически. Для этого надо установить модуль IIS под названием "Инициализация приложений" (Application Initialization), если он ранее не был установлен. Дальше надо зайти в дополнительные параметры вашего веб-приложения (или сайта, если оно развернуто в корне) и включить там Предварительная установка включена (preloadEnabled): True Да, перевод довольно корявый. Но какой есть. Скриншот: https://i.stack.imgur.com/piqK5.png Теперь осталось прописать один или несколько URL-адресов, по которым IIS будет сам делать запросы, пробуждая тем самым веб-приложение ото сна. Для этого надо зайти в редактор конфигурации веб-приложения, выбрать там раздел "system.webServer/applicationInitialization" и отредактировать коллекцию по умолчанию. Скриншот: https://i.stack.imgur.com/jms2L.png Эти настройки далее попадут в файл web.config. Если вы используете средства автоматического развертывания, то они могут перезатереть ваши настройки в этом файле. Тут есть два решения. Первое: необходимые адреса может прописать разработчик и сохранить вместе с остальным исходным кодом проекта. Второе: надо переключить уровень конфигурации в интерфейсе, чтобы ваши настройки попали в конфиг, лежащий в другом месте. Скриншот: https://i.stack.imgur.com/uThfr.png

Ответ 2



Может дело не в операционной системе и окружении, а в самом сайте? Судя по поведению ваш сайт медленно загружается именно в момент скачивания файлов, а далее браузер уже берет данные из кэша, поэтому все работает быстрее (через определенное время браузер снова запрашивает файлы из-за чего и возникают тормоза. Попробуйте выполнить аппаратную перезагрузку и посмотрите на waterfall в инструментах разработчика Chrome. Для аппаратной перезагрузки и очистки кэша - открываем инструменты разработчика, щелкаем правой кнопкой мыши на иконке обновления перед адресной строкой и выбираем соответствующий пункт. Вполне возможно, что на скорость влияют большие файлы шрифтов или изображений. Также при первой загрузке может идти долгий поиск DNS, но это уже надо смотреть по графику, сложно сказать навскидку. Также не помешает на сервере вести статистику (например, munin или любые другие средства, собирающие информацию о системе). Некоторые провайдеры увлекаются на хостинге/VDS срезанием ресурсов, так что может и из-за этого. Надо смотреть графики по процессору и времени отклика страницы. Если падают доступные процессорные ресурсы или увеличивается время отклика, то значит нужно изучать ситуацию на самом сервере.

Ответ 3



У меня была подобная проблема. НА VDS хостинге всего 1 гигабайт оперативки, и когда через RDP во время администрирования было открыто много окон, приложений, а выйдя с RDP я их забыл закрыть, оказалось что оперативной памяти не хватает и сайт очень тормозит. Решением было закрывать все лишние окна и приложения при выходе с RDP.