Страницы

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

среда, 24 октября 2018 г.

Компиляция sass документа при перезагрузке страницы

Я создал функцию, которая генерирует случайный цвет. Но возникла проблема - она не работает при перезагрузке страницы. Как мне сделать так, чтобы scss файл компилировался каждую перезагрузку? Можно на любой технологии.


Ответ

P.S. Изменения ответа за 23.10.2017 Я тут расхваливал webpack и даже за конкурсный вопрос 100 балов получил, но есть проблема, в той конструкции которую я привел, less отказывается читать background-image: url(путь к картинке) ; путь должен быть обязательно в одинарных кавычках, но используя новый приведенный пример файла webpack.config.js, там все исправлено. В комментах есть объяснения что к чему.
Предлагаю webpack, ниже привожу полную структуру. Не обязательно что-бы сервер был именно nodejs, но именно для webpack, nodejs должен присутствовать...
Файл в корне webpack.config.js. в примере ниже используется less, но нет абсолютно ни какой разницы, просто замените less на sass и естественно пакеты установки не less, а sass. Работоспособность проверена полностью, один минус, не показывает ошибки, надо быть внимательнее, когда пишите код на sass компилирует даже с ошибками. Можно просто создавать сотню файлов sass и все они будут прописываться в один css файл, лично для меня это удобно, подключаешь один css и все работает. Куда какие файлы прописать увидите в комментариях в файле webpack.config.js И еще забыл добавить, для того чтобы все файлы sass или less компилировались надо их импортировать в главный less или sass !!!
var path = require('path'); const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = { entry: "./less/main.less", // путь откуда берет less node: { fs: 'empty', net: 'empty' }, output: { path: __dirname + "/public/css", // путь куда вставлять компилированный css filename: "bundle.js" }, module: { rules: [{ test: /\.less$/, use: ExtractTextPlugin.extract({ fallback: "style-loader", use: ["css-loader", "less-loader"] }) }, { test: /\.(png|jpg|jpeg|svg|gif)$/, include: [ path.resolve(__dirname, './img/') // а тут надо прописать имя папки откуда будет брать все картинки ], use: [{ loader: 'file-loader', options: { name: './public/img/[hash].[ext]', } }] }, { test: /\.(ttf|eot|woff|woff2|png|jpg|jpeg|svg|gif)$/, loader: 'url-loader' }, ] }, plugins: [ new ExtractTextPlugin({ filename: 'main.css' // а тут надо прописать имя css которое вы хотите }) ] };
Далее привожу пример файл package.json там найдете команды запуска именно webpack, и увидите, что установить
{ "name": "********", "version": "1.0.0", "description": "***********************", "main": "serv.js", "scripts": { "start": "node serv", "watch": "webpack -w --config webpack.config.js"/*команда запуска webpack npm rum watch*/ }, "repository": { "type": "git", "url": "**********************************" }, "keywords": [ "short", "advertising", "site" ], "author": "***************", "license": "ISC", "homepage": "*******************", "dependencies": { "body-parser": "^1.18.2", "css-loader": "^0.28.7", "express": "^4.16.1", "fs": "0.0.1-security", "mongoose": "^4.12.1", "style-loader": "^0.19.0", "url-loader": "^0.6.2" }, "devDependencies": { "extract-text-webpack-plugin": "^3.0.1", "file-loader": "^1.1.5", "less": "^2.7.2", "less-loader": "^4.0.5", "webpack": "^3.6.0" } }

Как сделать прозрачное «отверстие» в блоке с фоном(background)?

Ситуация такая что есть блок с background, нужно в нем сделать отверстие(прозрачное) чтобы можно было наблюдать что за фоном.
Есть ли реализация без внедрения png svg и тд? Видел такую реализацию, но так и не понял как это было сделано
Есть ли какие-то идеи?


Ответ

Можно попробовать с помощью псевдоэлемента :after и огромной непрозрачной тени:
#hole { position: relative; width: 500px; height: 500px; margin: 0 auto; overflow: hidden; } #hole:after { content: ""; position: absolute; border-radius: 100%; width: 300px; height: 300px; left: 50%; top: 50%; transform: translate(-50%, -50%); box-shadow: 0px 0px 0px 2000px #000; } body { background: url('https://wallpaperbrowse.com/media/images/Wallpaper-1.png'); background-size: cover; }


Зачем в FileSplit нужен рандомный генератор?

Один из конструкторов FileSplit (класс из DataVec) имеет вид:
FileSplit(java.io.File rootDir, java.lang.String[] allowFormat, java.util.Random rng)
Зачем нужен аргумент Random rng?


Ответ

Там в методе initialize и в reset перемешивание происходит, если был передан Random
protected void initialize() { [...] if (randomize) { iterationOrder = new int[subFiles.size()]; for (int i = 0; i < iterationOrder.length; i++) { iterationOrder[i] = i; } RandomUtils.shuffleInPlace(iterationOrder, random); } [...] }
@Override public void reset() { if (randomize) { //Shuffle the iteration order RandomUtils.shuffleInPlace(iterationOrder, random); } }

Генерация 3-х мерного лабиринта

Я бы хотел реализовать генерацию трехмерного лабиринта, что-то вроде этого

Ничего путного по этой теме найти не удалось. Есть у кого идеи на эту тему?


Ответ

Для начала, определимся с тем, что же такое лабиринт, т.е. дадим первое определение лабиринта, которое впоследствии мы чуть-чуть модифицируем. Я буду рассматривать двумерный случай. Трёхмерный во всех его вариациях строится ровно так же.
Определение. Лабиринтом на плоскости будем называть связный неориентированный граф без петель, у каждой вершины которого не более 4 ребёр.
Довольно легко провести аналогию решётки-лабиринта nxm и лабиринта. Как это сделать? Достаточно рассмотреть клетку и заметить, что у каждой клетки есть 4 соседа (не берём граничные случаи):

Теперь можно убрать, например, одного соседа. Обычная ситуация в лабиринте:

Каждую клетку можно ассоциировать с вершиной. Наличие соседа - связывать с ребром. В таком случае, довольно очевидно, что определение более или менее корректное. С первого взгляда непонятно: для каждого ли лабиринта можно подобрать решётку-лабиринт, ровно как и наоборот. Здесь уже необходимо строгое доказательство, которое приводить смысла много не имеет.
Вообще говоря, для порождения самого лабиринта, строить граф в явном виде не обязательно. Я лишь заострил внимание на этом, дабы дать волю Вашей фантазии. Построение графа может быть полезно при более детальном изучении вопроса. Вам может быть важно, чтобы лабиринт обладал какими-нибудь свойствами. Может быть Вам захочется ввести некую "плотность" или разветвлённость лабиринта. В таком случае на помощь могут прийти именно графы.
Определение. Границей решётки или просто границей назовём такую вершину, координата которой на решётке равна: (x, m), или (n,x), или (1,x), или (n,x), где х -- любое число из промежутков [1,n] или [1,m].
Теперь же, перейдём к генерации лабиринта. Сделаем это так. Зададим матрицу nxm. Выберем одну точку на одной из границ. После этого запустим из этой точки обход в глубину в пределах решётки.
Для каждой точки лабиринта будем по очереди выбирать каждое из 4х направлений и случайным образом, с вероятность p, принимать решение, есть ли проход в этом направлении или его нет. Будем его выполнять до тех пор, пока суммарное количество точек на границе будет не более k. Как только это произойдёт, мы прекращаем наше выполнение действий.
Делая действия таким образом, можно получить очень неравномерный лабиринт. Поэтому можно критерий останова чуть-чуть изменить. Будем его выполнять процесс до тех пор, пока суммарное количество точек на границе будет не более k и на каждой из границ (всего границы, разумеется, 4), будет не менее k_i точек.
Теперь нам нужно выбрать выбрать начало и конец. Можно, конечно, взять любые 2 точки на границе, но в таком случае, может случиться, что путь от начала в конец окажется тривиальным (т.е. слишком простым и коротким). Для того, чтобы этого избежать, следует выбирать начальную и конечную точки на расстоянии друг от друга не менее чем d
Таким образом мы построили алгоритм генерации лабиринта с параметрами: k, k_i (4 шт), p, d
Советую обратить внимание на такую вещь как теория перколяции. В этой теории реализуется процесс, который я описал выше.
У меня валяются три реализации перколяционного процесса на питоне, матлабе и плюсах. Вы можете на них взгялнуть здесь: 1, 2, 3

Что лучше при поиске чисел Фибоначчи - рекурсия или простое сложение?

Почему поиск чисел Фибоначчи решается с помощью рекурсии? В интернете много примеров с рекурсией - чем простое сложение не нравится? С рекурсией решается быстрее, если искать до 21 числа, а вот все что больше уже намного быстрее решается простым сложением. Почему с рекурсией быстрее, ведь это получается больше почти 100 раз вызов самого себя?
public static void main(String[] args) { long l = System.nanoTime(); long findFib = 16; System.out.println("not recursion = " + fib(findFib)); l = System.nanoTime() - l; System.out.println("time = " + l); l = System.nanoTime(); System.out.println("recursion = " + recFib(findFib)); l = System.nanoTime() - l; System.out.println("time = " + l); }
private static long fib(long i) { long curr = 1; long previous = 0; for (long j = 0; j < i - 1; j++) { long temp = curr; curr += previous; previous = temp; } return curr; }
private static long recFib(long i) { if (i < 2) { return i; } return recFib(i - 1) + recFib(i - 2); }


Ответ

Ваши два вопроса построены одинаково - спрашивается, почему о неверных вещах. Потому что это на самом деле не так.
В дидактических целях, чтобы показать, что такое рекурсия. Чтобы показать, что неразумное применение рекурсии ведет к неработоспособной программе. С рекурсией не быстрее никогда - по крайней мере для чисел Фибоначчи и без мемоизации.
Сравнение вот таких функций
long long fibR(unsigned int N) { if (N < 2) return 1; return fibR(N-1) + fibR(N-2); }
long long fibI(unsigned int N) { if (N < 2) return 1; long long f0 = 1, f1 = 1; for(unsigned int i = 2; i <= N; ++i) { long long f = f0 + f1; f0 = f1; f1 = f; } return f1; }
на моей машине дает (ссылка на полный код ниже; простите, я на C++ работаю, но не думаю, что на Java что-то изменится :))
N(i) = 3 3 0 mks N(r) = 3 3 1 mks N(i) = 6 13 0 mks N(r) = 6 13 5 mks N(i) = 9 55 0 mks N(r) = 9 55 22 mks N(i) = 12 233 0 mks N(r) = 12 233 95 mks N(i) = 15 987 0 mks N(r) = 15 987 406 mks N(i) = 18 4181 0 mks N(r) = 18 4181 1718 mks N(i) = 21 17711 0 mks N(r) = 21 17711 7301 mks N(i) = 24 75025 0 mks N(r) = 24 75025 24896 mks N(i) = 27 317811 0 mks N(r) = 27 317811 86819 mks N(i) = 30 1346269 0 mks N(r) = 30 1346269 370024 mks N(i) = 33 5702887 0 mks N(r) = 33 5702887 1568399 mks
Примерно тот же результат получается и тут: https://ideone.com/rfjifS

CSS Grid колонки разной высоты

Как расположить колонки разной высоты друг под другом, при помощи Grid? Как показано на изображении.

Тут пример кода:
.gallery__grid { display: grid; grid-template-columns: repeat(3, 1fr); grid-gap: 30px; } .gallery__grid-item { background: #000; } .gallery__grid-item:nth-child(even) { height: 150px; } .gallery__grid-item:nth-child(odd) { height: 120px; }



Ответ

Как вы уже поняли CSS Grid позволяет генерировать разметку только с прямоугольными элементами. Поэтому чтобы у вас получилось, можно поиграться с position: relative и отрицательными margin
Пример (будет работать для любого кол-ва строк с элементами):
.gallery__grid { display: grid; grid-template-columns: repeat(3, 1fr); grid-gap: 15px; } .gallery__grid-item { background: orange; height: 120px; } .gallery__grid-item:nth-child(2) { height: 135px; margin-top: -15px; } .gallery__grid-item:nth-child(3n + 2) { position: relative; top: 15px; } .gallery__grid-item:nth-last-child(1), .gallery__grid-item:nth-last-child(3) { height: 135px; }


Данный пример будет работать корректно, если у нас 3 столбца и кол-во элементов кратно трём.

В каких случаях имеют смысл var-шаблоны?

В C# 7.0 появились var-шаблоны которые судя по документации всегда trueи нужны для создания новой переменной с таким же типом и значением.
Накидал тестовый метод, штука действительно работает.
private void TestPattern(object k) { if (k is var test) Console.WriteLine("Result: " + test.GetType() + " " + test); Console.ReadKey(); }
Однако нахожу ее абсолютно бессмысленной. Более того, код как по мне жутко не читабельный и не очевидный.
Так для каких ситуаций собственно нужен этот шаблон?


Ответ

Это может быть применимо для введения временной переменной в выражении, например
public void VarPattern(IEnumerable s) { if (s.FirstOrDefault(o => o != null) is var v && int.TryParse(v, out var n)) { Console.WriteLine(n); } }

Фигурная стрелка с плавным переходом CSS

Необходимо реализовать стрелку у сообщения такого рода:

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


Ответ

Рекомендую использовать SVG
* { margin: 0; padding: 0; } body { display: flex; justify-content: center; align-items: center; } .text { position: relative; background-color: dodgerblue; width: 200px; padding: 25px; margin: 25px; } .angle { position: absolute; top: -15px; left: -43px; }

Lorem ipsum dolor sit amet consectetur adipisicing elit. Minima eaque saepe porro ex laudantium debitis praesentium beatae dolores maiores voluptates, qui animi vero non cum quisquam adipisci placeat iste provident?


Определение настроек prod/dev по connection string

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

А dev версия выглядит так:

И сейчас это сделано через анализ адресной строки, в файле Views/Shared/_Layout.cshtml:
@functions{ private bool IsDevEnv() { return Context.Request.Host.Value.Contains("localhost"); } } .... @if (IsDevEnv()) { Polish Hub } else { Polish Hub }

Однако это не совсем то, что мне нужно: мне нужно проверять параметры sql server connection string, а не hostname сервера. (К сожалению, таковы особености appharbor'а по работе с core на текущий день - в классическом asp.net mvc нормально происходят замены переменных)
Как можно добраться до этих настроек (connection string)в asp.net core?
Можно ли как-то в view добраться до Configuration.GetConnectionString? Или, если нельзя, то с какого уровня определить переменную mode (prod/dev), чтобы пробрасывать её в layout страницы.


Ответ

До настроек во View можно добраться через @inject
Допустим у нас в appSettings.json написано такое
{ "SomeOption" : { "SomeProp" : 1000 } }
Создадим класс MyAppOptions и в нем создадим свойство с названием совпадающим с названием опции
public int SomeProp { get; set; }
Теперь перейдем к Startup.cs в нем у нас уже должно быть поле
private readonly IConfiguration _configuration;
которому присваивается значение через конструктор. Далее переходим в метод ConfigureServices(...) и добавляем такое
services.Configure(_configuration.GetSection("SomeOption"));
Теперь во View
@using Microsoft.Extensions.Options @inject IOptions options
@в нужном месте@ @options.Value.SomeProp

Изменение имени dll с исходного Microsoft.Win32.TaskScheduler.dll на my.dll делает её неработоспособной

Для работы с Планировщиком заданий Windows я использую библиотеку Task Scheduler (устанавливаю через Nuget Package Manager: https://archive.codeplex.com/?p=taskscheduler).
Если установить nuget пакет, выполнить сборку проекта, в папке с исполняемым файлом появится файл Microsoft.Win32.TaskScheduler.dll, на который есть ссылка в проекте. Если библиотеку (файл dll) вынуть из проекта, удалить пакет, положить на место и сделать ссылку на неё - всё будет работать так же нормально. Ничего нового.
Но вот стоит поменять имя файла библиотеки, снова сделать ссылку, удалив прежнюю, это дело работать уже не будет. Т.е. изменение имени dll (с исходного "Microsoft.Win32.TaskScheduler.dll" на, например, "my.dll") делает её неработоспособной... В чём проблема?


Ответ

Да, CLR устроена так, что в общем случае нельзя просто взять и переименовать сборку. По умолчанию, CLR при поиске сборки ориентируется на ее внутреннее имя (из метаданных), но при этом ищет не по внутреннему имени, а по имени файла, т.е. по строкам типа [application base] / [assembly name].dll и т.п. Если нужно, чтобы при поиске сборки использовалось имя файла, нужно использовать параметр codebase в конфигурации:
...

...

Если сборка использует строгое имя, нужно будет указать больше параметров:

Документация: How the Runtime Locates Assemblies

Можно ли удалить огромное количество файлов в директoрии?

Есть ли консольное решение следующей проблемы? В папка имеется очень-очень много файлов типа:
xaaaacqjz xaaaacqka xaaaacqkb xaaaacqkc xaaaacqkd xaaaacqke xaaaacqkf xaaaacqkg
Их там настолько много, что thunar просто перестает отвечать, в общем в гуйне не могу решить проблему.
Можно как-то их удалить командой rm? Можно было бы кочнено полностью выпилить папку, но там у меня слишком много годного материала. Помогите пожалуйста!


Ответ

вообще, конечно, удалить файлы можно программой rm
$ rm список файлов
в частности, к примеру, файлов в каталоге /путь/к/каталогу, подпадающих под маску xaaaa*
$ rm /путь/к/каталогу/xaaaa*
но если файлов так много, что полный их список не укладывается в ограничение на длину списка аргументов ($ getconf ARG_MAX покажет это ограничение — в байтах), то (ещё в процессе формирования списка аргументов) вы получите ошибку:
bash: /bin/rm: Argument list too long
в таком случае можно воспользоваться программой find
$ find /путь/к/каталогу -maxdepth 1 -type f -name xaaaa\* -delete

Язык C, преобразование unsigned -> signed

Согласно Стандарту, переполнение знакового есть неопределенное поведение...
Значит ли это, что классический случай:
unsigned int ui = UINT_MAX - rand() % 10; signed int si = ui;
Является неопределенным поведением?
Где можно найти как можно более полный перечень ситуаций, в которых возможно UB? Пускай и общее описание, без досконального разбора каждого случая.


Ответ

Переполнение при целочисленном преобразовании к знаковому типу не является неопределенным поведением. Результат при таком переполнении определяется реализацией или может привести к сигналу
6.3 Conversions 6.3.1 Arithmetic operands 6.3.1.3 Signed and unsigned integers [...] 3 Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.
К неопределенному поведению приводит знаковое целочисленное переполнение при выполнении арифметических вычислений, но не при выполнении целочисленных преобразований.

Перечисление ситуаций, в которых возникает неопределенное поведение можно найти в конце стандарта языка, в приложении J. Раздел J.2 Undefined behavior

Un/boxing в C# ; от object к int

Не могли бы вы подсказать, почему явный downcast числового object'a (без предварительного upcast'a) доступен только к int, применяя к другим типам данных выдает ошибку invalidCastException. При предварительном upcast'e всё понятно , но ожидал , что без предварительного upcast'a работать downcast не будет.
Update. Как поправили - речь идёт об boxing/unboxing, а не о downcast'е.


Ответ

Преобразования к object и обратно называются упаковка и распаковка
Особенностью распаковки value-типов является то, что нельзя распаковать один value-тип в другой.
В данном случае, так как в object уже хранится int, его нельзя распаковать в другую структуру.

Получение координат svg при анимации

Есть такая анимация в SVG
setInterval(function() { console.log(document.getElementById('star_path').getBBox()); }, 200);
Как в реальном времени получать координаты анимированного шарика? Вот такой например код показывает постоянно одни и те же координаты.


Ответ

Используйте getBoundClientRect, вместо getBBox(). Метод вернет объект с текущими координатами и размерами.
Возвращаемое значение — это объект TextRectangle, содержащий свойства только для чтения left, top, right и bottom, описывающие бокс с границами в пиксельном измерении. Значения top и left даются относительно верхнего левого угла порта просмотра.
const circle = document.getElementById('circle'); setInterval(function() { const {left, top} = circle.getBoundingClientRect(); console.log(`x: ${left}, y: ${top}`); }, 200);
NOTE:
left/top переменные - это значения верхнего левого угла, поэтому если вам нужно вычислить центр круга, тогда придется прибавить к этим координатам половину радиуса круга.
const circle = document.getElementById('circle'); setInterval(function() { const {left, top} = circle.getBoundingClientRect(); const circleR = parseFloat(circle.getAttribute('r')); const [circleX, circleY] = [left + circleR / 2, top + circleR / 2]; console.log(`x: ${circleX}, y: ${circleY}`); }, 200);
P.S.
const [circleX, circleY] = [left + circleR / 2, top + circleR / 2];
Это маленький хак, то же самое что и:
const circleX = left + circleR / 2; const circleY = top + circleR / 2;

Заменить текст в xml на заданный

Есть файл xml который имеет вид :
Xml has been renamed to New Xml Test has been renamed to Xml Xml has been renamed to Xml XmlXml has been renamed to New Xml Xml has been renamed to Xml
Нужно заменить добавить до всех слов Xml, слово New
Делаю так:
string prefix = "New"; string word = "Xml"; string regexPattern = $@"(?foreach (var node in xdoc.Descendants()) { node.Value = Regex.Replace(node.Value, regexPattern, replacement);
foreach (var attribute in node.Attributes()) { attribute.Value = Regex.Replace(attribute.Value, regexPattern, replacement); } }
return xdoc;
Замена происходит, но, почему то удаляются ноды и xml становится в виде:
New Xml has been renamed to New XmlTest has been renamed to XmlNew Xml has been renamed to XmlXmlNew Xml has been renamed to New XmlNew Xml has been renamed to New Xml
Что я делаю не так? В чем моя ошибка?


Ответ

xdoc.Descendants() возвращает первым элементом корень всего документа, т.е. тег test со всем его содержимым.
Свойство XElement.Value
Возвращает или задает сцепленное текстовое содержимое этого элемента.
Поэтому вы первой же итерацией просто уничтожаете все вложенные теги. Всё, дальше итераций не будет.
Починить можно так:
foreach (var node in xdoc.Root.Descendants())
или так:
foreach (var node in xdoc.Descendants("line1"))
Цикл по атрибутам надо будет вынести отдельно.
Еще один вариант (без правки заголовка цикла) — пропускать элементы, имеющие дочерние элементы:
if (!node.HasElements) node.Value = Regex.Replace(node.Value, regexPattern, replacement);
Тогда цикл по атрибутам можно оставить внутри.
(правильность самой регулярки не проверял)

Из Java в Objective-C

У меня есть программа, написанная на Java (для Android). Теперь требуется написать аналогичную для iOS. В моей программе модель достаточно хорошо отделена от UI и вся эта логика в iOS-программе будет такой же. Я начал переписывать всё это руками, но теперь понимаю, что это займет слишком много времени. Тем более когда будут появляться ошибки, надо будет вносить одни и те же изменения в оба приложения. Можно ли как-то по-быстрому сгенерировать Objectve-C код из Java кода?


Ответ

я бы не пытался идти таким путем. Все таки, у андроида и айОС разные модели поведения. Например, приложение на андроиде всегда должно быть готовым к тому, что его закроют, а вот под айОС приложению дается какое то время на завершение работы. Наличие-отсутсвие приложений в фоне, наличие уборщика мусора и необходимость следить за ресурсами. Поэтому, все таки правильнее просто переписать. Но есть один обходной путь. Андроид позволяет писать часть приложения на с/с++ (ndk, хотя это и не рекомендуется), для айОС, насколько мне известно, тоже можно на с писать. Поэтому, графическую часть пишем для каждой платформы свою, а сложную логику - просто перекомпилируем.

Паттерны объектного программирования.

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


Ответ

"Самых полезных" паттернов нет.

Тем не менее, существует набор предопределенных Design Patterns, введенных Э.Гаммой и его коллегами, известными как Gang of Four
И есть соответствующая книга, которая приводит их подробное описание и возможные сценарии использовании. Обычно [GoF - Design Patterns] рекомендуется для прочтения каждому человеку, который склонен называть себя программистом.

Хороший пример проекции книги Design Patterns на стандартную библиотеку Java вы можете найти в ответе на вопрос Examples of GoF Design Patterns.

Символ двоеточия в string

При работе с xml-файлами в C# потребовалось создать через linq2xml такой элемент: xml:space="preserve" Однако при попытке добавить его программно new XAttribute("xml:space", "preserve") Получаю такую ошибку: "Знак ":", шестнадцатеричное значение 0x3A, не может использоваться в именах." Как можно добавить string типа "x:y"? Чуть более полный код: xdoc.Element("root").Add(new XElement("data", new XAttribute("name", x.Key), new XAttribute("xmlspace", "preserve"),new XElement("value", x.Value)));
// Надо xml:space Если кто задается вопросом, "WTF is that?", отвечаю, это программное добавление локализационных ресурсов Visual Studio. (Изначально взято через linq2xml из файла ресурсов Java в Dictionary и потом конвертировано в файл ресурсов Visual Studio), и, да, я знаю толк в извращениях.


Ответ

А если так: XmlDocument.CreateElement("prefix", "name", "uri"); //для элементов new XAttribute(XNamespace.Xml + "space", "preserve"); //для атрибутов

Зачем нужны статические внутренние классы?

И когда их выгодно применять? Читал в википедии - так ничего и не понял.


Ответ

Они имеют смысл в основном как средство тестирования/отладки. Ну например: в классе может быть только 1 метод main() - точка входа/запуска. А если в вашем классе сделать несколько внутренних статических класса каждый со своим main(): public class My { public static class Test1 { public static void main(String[] args) {} } public static class Test2 { public static void main(String[] args) {} } } То у вас получится 2 точки входа: java My$Test1 java My$Test2 оч. удобно. Ну и плюс сохраняется возможность доступа из внутреннего класса к приватным членам внешнего класса.

Что вы думаете о возможности создания вычислимой (по Тьюринга) модели разума (сознания, души)? [закрыт]

Если возможна, будет ли эта модель "настоящей" душой (то есть требуется ли для "настоящести" биологический мозг)? Если нет, верите ли вы в возможность научного исследования и описания невычислимого разума?


Ответ

Верю. P.S. Аргументов нет, потому что категория верю/не верю не подразумевает аргументацию Update Придется аргументировать раз такая пьянка пошла :) Вопрос на самом то деле упирается не в верю/не верю в модель разума, а в верю/не верю в душу. А душа есть субстанция с которой оперирует Господь. То есть все упирается в верю/не верю в Бога. Если душу можно смоделировать машиной, значит Бога нет. Если нельзя значит Бог есть. Путем несложным логических выкладок теперь можно легко убедиться кто в этой дискуссии верит в Бога, а кто атеист.

Удаление строк из таблицы SQL

Есть таблица с такой структурой COL1 | COL2 | COL3 -----+------+----- a | d | t -----+------+----- d | t | a -----+------+----- a | t | d -----+------+----- m | n | l -----+------+----- l | m | n Записи, которые могут быть получены из других записей перестановкой значений в столбцах, должны выводиться только один раз. В данном случае ответ будет такой: COL1 | COL2 | COL3 -----+------+----- a | d | t -----+------+----- l | m | n Необходимо решить задачу при помощи стандартного SQL Подскажите пож-та с чего начать и как организовать алгоритм


Ответ

Решение задачи оказалось намного проще. Может-быть кому-нибудь еще поможет) select distinct least(col1,col2,col3) as col1 ,greatest(col1,col2,col3) as col2 ,case when col1 not in (least(col1,col2,col3) ,greatest(col1,col2,col3)) then col1 when col2 not in (least(col1,col2,col3) ,greatest(col1,col2,col3)) then col2 else col3 end col3 from table1;

Удаление Ruby c Windows

Как правильно удалить Ruby, чтоб файлы не остались и корректно работала командная строка и т.д
UPD: Win 7 Ultimate 32x. Ставил rubyinstaller с официального сайта


Ответ

В операционной системе Windows необходимо удалить папку и почистить переменные окружения в «Свойства системы → Переменные среды...», удалите все что связанно с Ruby.

Отправляя письма через форму на сайте, письма приходят с неверной кодировкой

Здравствуйте! Написал простенький скрипт обратной формы на php + jquary. Сам скрипт с функцией mail() echo "Ваше Ф.И.О. :".$name."
"; echo "Ваш контактный телефон :".$email."
"; echo "Время и дата :".$sug."
"; echo "Ваш запрос отправлен. Спасибо вам за ваш интерес к нашей компании!";
$from = 'test@mail.ru'; $emailTo = 'test@mail.ru'; $subject = '=?UTF-8?B?'.base64_encode('Запрос прайс листа с сайта: test').'?='; $headers = 'Content-type: text/plain; charset=utf-8'; $headers .= "From: ". $from ." <". $from .">
"; $body = "Ф.И.О. контактного лица: $name

Контактный телефон клиента: $email

Время и дата удобное для звонка ему:
$sug";
$headers = 'C сайта: test <'.$emailTo.'>' . "
" . 'Отправитель: ' . $name . "
" ; $headers .= "Date: ". date('D, d M Y h:i:s O') ."
";
mail($emailTo, $subject, $body, $headers, '-f'. $from );
$emailSent = true; }?> В данном скрипте проблему с заголовком письма решил, если письмо отправляю на локальном сервере в denwer и читаю их в Thunderbird то с кодировкой проблем нет, как только выложил его на виртуальный сервак и отправил письмо на почтовый ящик размещенный на mail.ru, появляются крокозябры: C я│п╟п╧я┌п╟: test п·я┌п©я─п╟п╡п╦я┌п╣п╩я▄: я┌п╣я│я┌п╦я─п╬п╡п╟п╫п╦п╣ Date: Mon, 24 Jun 2013 11:03:16 +0400
п╓.п≤.п·. п╨п╬п╫я┌п╟п╨я┌п╫п╬пЁп╬ п╩п╦я├п╟: я┌п╣я│я┌п╦я─п╬п╡п╟п╫п╦п╣
п п╬п╫я┌п╟п╨я┌п╫я▀п╧ я┌п╣п╩п╣я└п╬п╫ п╨п╩п╦п╣п╫я┌п╟: я┌п╣я│я┌п╦я─п╬п╡п╟п╫п╦п╣
п▓я─п╣п╪я▐ п╦ п╢п╟я┌п╟ я┐п╢п╬п╠п╫п╬п╣ п╢п╩я▐ п╥п╡п╬п╫п╨п╟ п╣п╪я┐: я┌п╣я│я┌п╦я─п╬п╡п╟п╫п╦п╣ Тема письма отображается верно. Прошу помощи разобраться в данной проблеме.


Ответ

Ну как бы все пользуются для почты http://phpmailer.worxware.com/. Но в вашем случаи есть прям в документации ответ http://php.net/manual/en/function.mail.php : function mail_utf8($to, $subject = '(No subject)', $message = '', $from) { $header = 'MIME-Version: 1.0' . "
" . 'Content-type: text/plain; charset=UTF-8' . "
" . 'From: Yourname <' . $from . ">
"; mail($to, '=?UTF-8?B?'.base64_encode($subject).'?=', $message, $header); }

Как в Android создать набор полей с автопереходом между ними?

Как в Android (2.3+) cоздать список полей, например, для ввода IP-адреса ... ? Причем, чтобы пользователь активировал поле и просто набивал цифры, например 010001225001 -> 10.001.225.001. Если делать строковое поле ввода, то в нем не получается автоматический перескок через точки. Начальное содержимое строкового поля не сохраняется, так что подсказка вида xxx.xxx.xxx.xxx будет стерта вводом и все. Если делать набор полей с цифрами - то по активации первого поля (010) оно так и остается активированным и для перехода во второе поле (001) надо еще раз кликать на следующее поле (фокус остается на первом поле, а надо бы, чтобы он перескочил на второе поле).


Ответ

Мне кажется, что Вам нужно создать список Ваших EditText. Затем на каждый EditText повесить по TextWatcher'у и при достижении в каждом из них 3-х цифр переводить фокус на следующий EditText. Так, моя догадка была верна. Вот Вам работающий код. Извините, написан чуть некрасиво, но я проверил - всё работает так, как Вы описали в вопросе. Это самый простой xml с 4-мя EditText.




А это уже само Activity, в котором происходит нужная работа. package com.blogspot.leved_notes.answerhashcode;
import java.util.ArrayList;
import android.os.Bundle; import android.app.Activity; import android.text.Editable; import android.text.TextWatcher; import android.widget.EditText;
public class MainActivity extends Activity implements TextWatcher {
int current; ArrayList array;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
current = 0; array = new ArrayList(4);
EditText edit1 = (EditText) findViewById(R.id.editText1); EditText edit2 = (EditText) findViewById(R.id.editText2); EditText edit3 = (EditText) findViewById(R.id.editText3); EditText edit4 = (EditText) findViewById(R.id.editText4);
edit1.addTextChangedListener(this); edit2.addTextChangedListener(this); edit3.addTextChangedListener(this); edit4.addTextChangedListener(this);
array.add(0, edit1); array.add(1, edit2); array.add(2, edit3); array.add(3, edit4); }
@Override public void afterTextChanged(Editable s) { if (s.length() == 3) { current++; if (current < 4) { array.get(current).requestFocus(); } } }
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
@Override public void onTextChanged(CharSequence s, int start, int before, int count) { }
}

Как открыть порт в Ubuntu?

Я новичок в ubuntu, поэтому никак не могу понять, почему порт не открывается и как это всё-таки сделать. Подскажите, пожалуйста!Я пробовал открыть порт в iptables, но, как я понял, iptables служат для управления файерволлом ufw, а при вводе команды sudo ufw status получаю ответ:sudo: ufw: command not foundКак в таком случае открыть порт? Гугление мне посоветовало лишь iptables.На всякий случай приведу выход команды netstat -an | grep LISTENtcp 0 0 127.0.0.1:25 0.0.0.0:* LISTENtcp 0 0 127.0.0.1:953 0.0.0.0:* LISTENtcp 0 0 127.0.0.1:587 0.0.0.0:* LISTENtcp 0 0 0.0.0.0:80 0.0.0.0:* LISTENtcp 0 0 5.231.61.235:53 0.0.0.0:* LISTENtcp 0 0 127.0.0.2:53 0.0.0.0:* LISTENtcp 0 0 127.0.0.1:53 0.0.0.0:* LISTENtcp 0 0 0.0.0.0:22 0.0.0.0:* LISTENtcp 0 0 127.0.0.1:631 0.0.0.0:* LISTENtcp6 0 0 ::1:953 :::* LISTENtcp6 0 0 :::53 :::* LISTENtcp6 0 0 :::22 :::* LISTENtcp6 0 0 ::1:631 :::* LISTENunix 2 [ ACC ] STREAM LISTENING 3215411995 /var/run/cups/cups.sockunix 2 [ ACC ] STREAM LISTENING 3215409707 /var/run/avahi-daemon/socketunix 2 [ ACC ] STREAM LISTENING 3215403381 @/com/ubuntu/upstartunix 2 [ ACC ] STREAM LISTENING 3215406175 /var/run/dbus/system_bus_socketunix 2 [ ACC ] STREAM LISTENING 3215553140 /var/run/sendmail/mta/smcontrolunix 2 [ ACC ] STREAM LISTENING 3215421071 /var/run/acpid.socketunix 2 [ ACC ] SEQPACKET LISTENING 3215405745 /run/udev/controlunix 2 [ ACC ] STREAM LISTENING 3215427067 /var/run/saslauthd/muxТо есть вроде как 53-й порт открыт... Как бы ещё портов открыть?


Ответ

Ваш листинг это не открытые порты, а вывод того кто какие порты слушает. Если вы хотите например открыть порт 53 по tcp, используя утилиту iptables : iptables -I INPUT -p tcp -m tcp --dport 53 -j ACCEPT

Как отменить (откатить) действие git pull?

Подскажите, пожалуйста, решение проблемы:
Есть две ветки: sphere и tags
Я находился в ветке sphere и случайно сделал git pull origin tags, потом, заметив, что написал неправильно, и не посмотрев, что мердж прошел с конфликтами, сделал git pull origin sphere, и у меня в ветку влились все новые изменения из sphere
Как мне вернуть код к состоянию до первого pull?


Ответ

git reset --hard git checkout sphere git reflog # Находите хэш коммита, в котором вы находились до первого pull-а. # Будет что-то вроде "8f05e00 HEAD@{4}: checkout: moving from master to sphere" # или "4c31200 HEAD@{10}: commit: Awesome feature implemented." git reset --hard [нужный хэш] Ну и я бы не рекомендовал использовать "git pull" вообще, потому как эта команда берет на себя слишком много функций и ее поведение неочевидно. Рекомендую разобраться поподробнее, как работает git, и использовать fetch + merge или fetch + rebase. Я лично предпочитаю второе, но это дело вкуса.

Зачем Apple придумала язык программирования Swift?

Чем не устроил их Objective-C? Какие преимущества у Swift перед Objective-C?


Ответ

Swift — гораздо более современный язык, не отягощённый проблемами совместимости с C. Добавить фичи наподобие безопасности памяти (memory safety), обобщённых классов/методов (generics), необнуляемых ссылок (non-nullable reference types) было бы очень сложно, оставаясь в рамках Objective C. (Сравните, например, лямбды в Objective C и в Swift'е.) Синкатсис, да и семантика C хороши для низкоуровневых языков (каким, например, C и является), но высокоуровневые фичи проще делать на другой основе.

Как обращаться к методам класса, заданного динамически?

В текущем классе необходимо программно определять имя другого класса (вида "ClassNumPath + i" ) и далее вызывать его методы.
Файлы классов ClassNumPath0.java (а так же ClassNumPath1.java .. ClassNumPath5.java) существуют и их методы вызываются без ошибок, если обращаться к ним в коде напрямую, например:
ClassNumPath0.initPositions();
или
ClassNumPath4.initPositions();
.. то никаких проблем нет - все работает как надо, отрисовка в onDraw производится и прочее... Но мне нужно определять имя класса ClassNumPathХ динамически и иметь возможность менять это имя имя класса по ходу действия.
Часть кода над которым я бьюсь:
public class ClassNumPath extends SurfaceView implements SurfaceHolder.Callback { ... int currentNum = 5; String currentClassName; Class cClass; ...
@Override protected void onDraw(Canvas canvas) { if (needInitialazation) { currentClassName = "com.mytestapp.testapp.ClassNumPath" + currentNum; cClass = Class.forName(currentClassName);
cClass.initPositions(); // Ошибка: Cannot resolve method 'initPositions()' ClassNumPath5.initPositions(); // А это работает правильно
Log.d("INF", "currentClassName = " + currentClassName); Log.d("INF", "cClass = " + cClass); // Эти логи выдают правильное имя класса com.mytestapp.testapp.ClassNumPath5 } ... cClass.checkState(); // Ошибка: Cannot resolve method 'checkState()' ClassNumPath5.checkState(); // А это работает правильно ... }
Итак, вопрос:
Каким образом можно обращаться к методам класса, чье имя было задано динамически?
Или, пожалуйста, подскажите вариант как по-другому решить задачу. Не хочется выстраивать большую конструкцию с операторами типа Case с выбором нужного имени класса в зависимости от значения currentNum, так как классов ClassNumPathХ может быть более 100 штук.


Ответ

Благодарю @nofate за помощь! Я использовал предложенное им Решение №2 с объявлением интерфейса. Действительно, все методы в пронумерованных классах ClassNumPathX одинаковы и вовсе не обязаны быть статическими. Единственное замечание, в строке:
IClassNumPath classNumPath = (IClassNumPath) clazz.newInstance();
Android Studio выдавал ошибку на IClassNumPath, поэтому я заменил его на название интерфейса ClassNumPath (без префикса I):

В итоге решение получилось такое:
В классе ClassNumPath объявил интерфейс NumPath с набором общих методов для всех нумерованных классов 'ClassNumPathX`
public class ClassNumPath extends SurfaceView implements SurfaceHolder.Callback { ... public static NumPath cNumPath; ... // дать имя ClassNumPath интерфейсу внутри класса ClassNumPath уже нельзя public interface NumPath { void initPositions(); void checkState(); } ... @Override protected void onDraw(Canvas canvas) { if (needInitialazation) { currentClassName = "com.mytestapp.testapp.ClassNumPath" + currentNum; Class clazz = Class.forName(currentClassName); NumPath cNumPath = (NumPath) clazz.newInstance(); cNumPath.initPositions(); } ... // Поскольку cNumPath объявлен как public, то можно пользоваться им в любом месте cNumPath.checkState(); ... } }
В самих нумерованных классах ClassNumPathХ даже и не пришлось ничего особо менять. Только добавил implements ClassNumPath.NumPath и @Override к методам и убрал из них static
public class ClassNumPath4 implements ClassNumPath.NumPath { ... @Override public void initPositions() { ... }
@Override public void checkState() { ... } }

Как добавить или удалить элемент массива?

Есть массив, например:
var m = [1, 2, 3, 4, 5];
Как добавить элемент в массив? Как удалить элемент массива?


Ответ

Добавление
Array.prototype.push(element1, ..., elementN)[MDN][спецификация] добавляет элемент(ы) в конец массива. Возвращает новую длину массива.
m.push(6); > 6 // m равно [1, 2, 3, 4, 5, 6] m.push(7, 8, 9); > 9 // m равно [1, 2, 3, 4, 5, 6, 7, 8, 9] Array.prototype.unshift(element1, ..., elementN)[MDN][спецификация] добавляет элемент(ы) в начало массива. Возвращает новую длину массива.
m.unshift(0); > 6 // m равно [0, 1, 2, 3, 4, 5, 6] m.unshift(3, 2, 1); > 9 // m равно [3, 2, 1, 0, 1, 2, 3, 4, 5] Array.prototype.splice(start, deleteCount[, item1[, item2[, ...]]])[MDN][спецификация] изменяет содержимое массива, удаляя элементы и/или добавляя новые. Возвращает массив удалённых элементов.
m.splice(2, 0, 2.5); > [] // m равно [1, 2, 2.5, 3, 4, 5] m.splice(5, 0, 4.25, 4.5, 4.75); > [] // m равно [1, 2, 2.5, 3, 4, 4.25, 4.5, 4.75, 5] m.splice(5, 3, 4.33, 4.66); > [4.25, 4.5, 4.75] // m равно [1, 2, 2.5, 3, 4, 4.33, 4.66, 5] Можно изменить свойсто .length массива, чтобы добавлять элементы undefined в конец.
m.length = 7; > 7 // m равно [1, 2, 3, 4, 5, undefined, undefined]
Удаление
Array.prototype.pop()[MDN][спецификация] удаляет последний элемент массива. Возвращает удалённый элемент.
m.pop(); > 5 // m равно [1, 2, 3, 4] Array.prototype.shift()[MDN][спецификация] удаляет первый элемент массива. Возвращает удалённый элемент.
m.shift(); > 1 // m равно [2, 3, 4, 5] Array.prototype.splice(start, deleteCount[, item1[, item2[, ...]]])[MDN][спецификация] изменяет содержимое массива, удаляя элементы и/или добавляя новые. Возвращает массив удалённых элементов.
m.splice(2, 1); > [3] // m равно [1, 2, 4, 5] m.splice(1, 2); > [2, 4] // m равно [1, 5] Можно изменить свойсто .length массива, чтобы удалять последние элементы.
m.length = 3; > 3 // m равно [1, 2, 3]

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

Здравствуйте. Меня очень интересует, как, например, в браузере google chrome (и не только) вкладка помещается в другое окно при перетаскивании? Это ведь не DragDrop. Что тогда? Все события мыши передаются только в то окно, которое я тащу, тогда как мне определить, что курсор мыши находится на панели вкладок другого окна, которое под перетаскиваемым?
Просьба не давать ссылки на готовые контролы табов, в которых это реализовано. Ну или с конкретным файлом и строкой. Потому что я пытался найти в них, как это реализовано, но не смог (на гитхабе).


Ответ

Ну вот вам пример.
Для начала, создадим окно, которое умеет определять, какому из экземпляров принадлежит точка на экране. Положим в окно контейнер для перемещаемых элементов.

(Код, работающий с Z-порядком, взят из этого ответа.)
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop;
namespace CrossWindowDrop { public partial class DropContainerWindow : Window { public DropContainerWindow() { InitializeComponent(); }
// добавить перемещаемый элемент public void AcceptActor(Actor actor) { Arena.Children.Add(actor); }
// убрать перемещаемый элемент public void ReleaseActor(Actor actor) { Arena.Children.Remove(actor); }
// найти самое верхнее окно для данной точки public static DropContainerWindow BestTarget(Point screenPoint) { return AllByZOrder().FirstOrDefault(w => { var arena = w.Arena; var arenaPoint = arena.PointFromScreen(screenPoint); return arenaPoint.X >= 0 && arenaPoint.Y >= 0 && arenaPoint.X < arena.ActualWidth && arenaPoint.Y < arena.ActualHeight; }); }
// получить список всех окон, отсортированный по Z-порядку // для обхода окон приходится использовать WinAPI, т. к. // WPF не знает о Z-порядке static IEnumerable AllByZOrder() { var byHandle = App.Current.Windows .OfType() .ToDictionary(w => ((HwndSource)PresentationSource.FromVisual(w)) .Handle);
for (IntPtr hWnd = GetTopWindow(IntPtr.Zero); hWnd != IntPtr.Zero; hWnd = GetWindow(hWnd, GW_HWNDNEXT)) { DropContainerWindow w; if (byHandle.TryGetValue(hWnd, out w)) yield return w; } }
// вспомогательные WinAPI-функции и константы const uint GW_HWNDNEXT = 2; [DllImport("user32")] static extern IntPtr GetTopWindow(IntPtr hWnd); [DllImport("user32")] static extern IntPtr GetWindow(IntPtr hWnd, uint wCmd); } }
Теперь, сам перемещаемый элемент. Реализуем его как UserControl


using System; using System.Windows; using System.Windows.Controls; using System.Windows.Input;
namespace CrossWindowDrop { public partial class Actor : UserControl { public Actor() { InitializeComponent(); }
// эти три свойства валидны лишь на время движения
// запоминает позицию мыши внутри контрола Point relativeMousePos; // контейнер FrameworkElement parent; // окно, в котором мы находимся в данный момент DropContainerWindow window;
// на нажатии мыши начинаем движение void OnMouseDown(object sender, MouseButtonEventArgs e) { parent = (FrameworkElement)this.Parent; window = (DropContainerWindow)Window.GetWindow(this); relativeMousePos = e.GetPosition(this); // подписываемся на перемещение мыши MouseMove += OnDragMove; // и захватываем mouse capture Mouse.Capture(this); }
// при отпускании мыши прекращаем движение void OnMouseUp(object sender, MouseButtonEventArgs e) { // отписываемся от перемещения мыши MouseMove -= OnDragMove; // обновляем наше местоположение UpdatePosition(e); // отпускаем mouse capture Mouse.Capture(null); window = null; parent = null; }
void OnDragMove(object sender, MouseEventArgs e) { UpdatePosition(e); }
void UpdatePosition(MouseEventArgs e) { // абсолютное положение точки на экране var screenPoint = PointToScreen(relativeMousePos); // находим наиболее подходящее окно var bestWindow = DropContainerWindow.BestTarget(screenPoint); // если мы надо окном, и это не текущее окно... if (bestWindow != null && bestWindow != window) MigrateTo(bestWindow); // ... переезжаем! // позиция мыши относительно нашего контейнера var point = e.GetPosition(parent); // перемещаемся в нужную позицию Canvas.SetLeft(this, point.X - relativeMousePos.X); Canvas.SetTop(this, point.Y - relativeMousePos.Y); }
// самое интересное: переезд в новое окно void MigrateTo(DropContainerWindow newWindow) { // отпускаем мышь - наш контрол пересоздастся в другом окне Mouse.Capture(null); // просим наше окно выписать отпустить нас window.ReleaseActor(this); // а новое - принять newWindow.AcceptActor(this); // подправляем наши свойства parent = (FrameworkElement)this.Parent; window = newWindow; // и снова захватываем мышь Mouse.Capture(this); // вот и всё } } }
Ну и добавьте главную программу по вкусу.


using System.Windows; using System.Windows.Controls; using System.Windows.Media;
namespace CrossWindowDrop { public partial class App : Application { protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); var w1 = new DropContainerWindow() { Title = "Window 1" }; var actor1 = new Actor() { Background = Brushes.Violet }; var actor2 = new Actor() { Background = Brushes.Green }; Canvas.SetLeft(actor2, 50); w1.AcceptActor(actor1); w1.AcceptActor(actor2); w1.Show(); new DropContainerWindow() { Title = "Window 2" }.Show(); new DropContainerWindow() { Title = "Window 3" }.Show(); } } }
Всё! Теперь вы можете таскать цветные квадраты из одного окна в другое.

Получение длинных SMS сообщений, разбитых на части, на Android

Пишу небольшое приложение, одна из функций - обработка сообщений.
Я взяла код получения sms сообщения. Всё работает, но при получении длинного sms оно разбивается на несколько частей. Нужно собрать все части одной sms в одну строку и проверить что сообщение получено полностью.
Поиски вывели на несколько вариантов, но там создаётся массив в котором в качестве ключа используется номер отправителя, это позволяет собрать все части сообщения в одну строку, но не гарантирует получения всех частей sms.
Я изучала документацию по PDU но не смогла понять некоторые вещи.
Как узнать разбито ли сообщение на части? Как узнать количество частей? Как узнать номер части обрабатываемой прямо сейчас?
Прошу вашей помощи.
public class SMSMonitor extends BroadcastReceiver { private static final String ACTION = "android.provider.Telephony.SMS_RECEIVED";
@Override public void onReceive(Context context, Intent intent) { if (intent != null && intent.getAction() != null && ACTION.compareToIgnoreCase(intent.getAction()) == 0) { Object[] pduArray = (Object[]) intent.getExtras().get("pdus"); SmsMessage[] messages = new SmsMessage[pduArray.length]; for (int i = 0; i < pduArray.length; i++) { messages[i] = SmsMessage.createFromPdu((byte[]) pduArray[i]); } StringBuilder bodyText = new StringBuilder(); for (SmsMessage message : messages) { bodyText.append(message.getMessageBody()); } String body = bodyText.toString(); Observer.getInstance().send(new SmsEvent(body)); abortBroadcast(); } } }


Ответ

Опишу приблизительный алгоритм. Предположим есть некая строка pdu
07919772929090F3440B919778563412F00008519042212124618C050003F50201041D043E0447044C002C00200443043B043804460430002C00200444043E043D04300440044C002C00200430043F04420435043A0430002C000A0411043504410441043C044B0441043B0435043D043D044B0439002004380020044204430441043A043B044B043900200441043204350442002E000A04160438043204380020043504490435
где:
07919772929090F3 - SCA 44 - ProtocolDataUnitType 0B919778563412F0 - OriginatorAdrress 00 - ProtocolIdentifier 08 - DataCodingScheme 51904221212461 - ServiceCenterTimeStamp 8C - UserDataLength 050003F50201 - UDHI 041D043E0447044C002C00200443043B043804460430002C00200444043E043D04300440044C002C00200430043F04420435043A0430002C000A0411043504410441043C044B0441043B0435043D043D044B0439002004380020044204430441043A043B044B043900200441043204350442002E000A04160438043204380020043504490435 - UserData
так вот, то что вас интересует находится в UDHI:050003F50201
02 - это количество сообщений, 01 - порядковый номер. Определить, что есть UDHI внутри UserData можно по ProtocolDataUnitType - в нашем случае 44(Hex). Данную hex-строку переведем в байт и посмотрим значение 6 бита, если он равен 1, то тогда UserData содержит UDHI
Надеюсь я смог Вам помочь в освоении этого непростого протокола.

Как работает интерфейс INotifyPropertyChanged?

Собственно сабж: как изнутри работает данный интерфейс? Что происходит при вызове метода NotifyPropertyChanged(string propertyName)? Как UI элемент узнает, что что-то произошло и нужно "перерисоваться"? Объясните пожалуйста. Чем подробнее - тем лучше)


Ответ

Если вы имплементируете интерфейс INotifyPropertyChanged, то вы должны определить event PropertyChanged, и отправлять его каждый раз, когда значение изменится.
Если у вас есть привязка к какому-то свойству, то Binding в числе прочего проверяет, реализует ли binding source (то есть, объект, к свойству которого происходит binding), этот интерфейс, и если да, то подписывается на этот самый event. По приходу event'а значение свойства перечитывается (через reflection).

Дополнение: А что происходит с ItemsSource? А для него интересен интерфейс INotifyCollectionChanged, который сообщает о том, что в коллекции появились/исчезли элементы.
Если вы привязываете ItemsSource в ListView к коллекции, Binding заботится о том, чтобы ListView знал текущее значение самой коллекции. То есть, если вы коллекцию подмените на другую коллекцию, об этом сообщит Binding. А вот нотификация об изменении списка элементов коллекции происходит следующим образом.
Когда ListView видит, что объект коллекции поменялся (эту информацию поставляет Binding), он самостоятельно проверяет наличие интерфейса INotifyCollectionChanged, и если коллекция его поддерживает, подписывается на событие CollectionChanged. Когда это событие приходит, в нём есть NotifyCollectionChangedEventArgs, который содержит информацию о том, что именно произошло, какие элементы добавились (и куда), а какие исчезли (и откуда). Имея эту информацию, ListView может перестроить список.
Заметьте, что обыкновенный List не реализует интерфейс INotifyCollectionChanged, поэтому если в привязке лежит List, ListView автоматически обновляться не будет. Обычно никто не реализует INotifyCollectionChanged самостоятельно, а пользуются готовыми коллекциями. Например, ObservableCollection

Побитовый сдвиг массива

Вообще мне нужно последовательно (побитно) передать и потом принять пакет длиной 48 бит.
Если бы пакет был длиной 32 бита, то решение могло бы быть примерно такое:
unsigned long data=0x12345678;
for(i=0;i<32;i++){ if(data & 0x80000000) setb_MOD; else clrb_MOD; data <<= 1; }
Этот код компилируется очень приятно и компактно. Именно так я бы и сделал на ассемблере:
code<<=1; ac: 88 0f add r24, r24 ae: 99 1f adc r25, r25 b0: aa 1f adc r26, r26 b2: bb 1f adc r27, r27 b4: 80 93 63 00 sts 0x0063, r24 b8: 90 93 64 00 sts 0x0064, r25 bc: a0 93 65 00 sts 0x0065, r26 c0: b0 93 66 00 sts 0x0066, r27
Но т.к. пакет имеет длину 48 бит, приходится обяъвлять его как массив и сдвигать его побайтно в цикле:
unsigned char data[6]={0x12,0x34,0x56,0x78,0xAB,0xCD};
for(i=0;i<48;i++){ if(data[5] & 0x80) setb_MOD; else clrb_MOD; for(j=5;j>0;j--){ data[j]<<=1; if(data[j-1] & 0x80) data[j]+=1; } data[0] <<= 1; }
Результаты компиляции несколько зависят от настроек оптимизатора, видно, что делает он ровно то, что ему и положено: т.е. компилирует он довольно буквально и не использует очевидную для человека коснтрукцию (см. выше). Вот что получается:
for(j=5;j>0;j--){ code[j]<<=1; a8: 82 91 ld r24, -Z aa: 88 0f add r24, r24 ac: 80 83 st Z, r24 if(code[j-1]&0x80) ae: 9e 91 ld r25, -X b0: 97 fd sbrc r25, 7 b2: 13 c0 rjmp .+38 ; 0xda <__vector_2+0x74> clrb_MOD; } else{ setb_MOD; } for(j=5;j>0;j--){ b4: 80 e0 ldi r24, 0x00 ; 0 b6: a3 36 cpi r26, 0x63 ; 99 b8: b8 07 cpc r27, r24 ba: b1 f7 brne .-20 ; 0xa8 <__vector_2+0x42> code[j]<<=1; if(code[j-1]&0x80) code[j]+=1; }
Мне бы очень хотелось избежать использования инлайн вставок кода на ассемблере. Во-первых по-тому, что я не очень владею этой техникой и совершенно не представляю как мне обращаться из ассемблерного кода к переменным, объявленным в C. Хотя, я точно знаю, что все это возмжоно.
Есть ли еще какие-то альтернативы получить оптимальный код?


Ответ

Вы все то же самое могли бы сделать, используя тип uint64_t или unsigned long long
Например,
#include
//...
uint64_t data = 0x123456780123;
for ( i = 0; i < 48; i++ ) { ( data & 0x8000000000 ) ? setb_MOD : clrb_MOD; data <<= 1; }

Создание круга, поделенного на сектора с сегментами

Мне нужно нарисовать вот такой вот элемент в WPF. Каждому сегменту я должен иметь возможность указать его уникальный цвет. Также требуется, чтобы этот элемент занимал все доступное ему место. В голову приходят варианты только с полным описанием всей логики отрисовки в Code-Behind или созданием собственной панели (но это еще сложнее выйдет). Может это как-нибудь можно в xaml описать?


Ответ

Ну что же, чистого решения на XAML'е у меня не вышло, кое-где пришлось применять тригонометрию. Но почти чистое решение есть.
Начнём с простого случая: размер квадратного поля известен заранее. Пускай он будет 200 × 200.
Для того, чтобы нарисовать кусочек интерфейса, нам нужно немного покопаться в PathGeometry. Для первого сегмента пишем нечто вот такое:

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

Добавим вторую точно такую же часть, но с другим углом поворота:

Результат обнадёживает:

Хорошо, теперь попробуем добавить текстовую метку в середину каждого куска. Для начала, мы не хотим заморачиваться с динамическим вычислением размера текста, а хотим центрировать текст относительно данной точки. Но если положить текст в контейнер нулевого размера, то он обрежется границами контейнера. Поэтому сделаем кастомный декоратор, который будет (1) не обрезать контент, (2) центрировать его внутри себя, и (3) обладать нулевым размером.
class CenteringNoClipper : Decorator { // не обрезаем контент своими краями protected override Geometry GetLayoutClip(Size layoutSlotSize) { return null; }
protected override Size MeasureOverride(Size constraint) { // даём контенту сколько угодно места Child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); // а сами занимаем ноль return new Size(); }
protected override Size ArrangeOverride(Size arrangeSize) { var childSize = Child.DesiredSize; // центрируем контент в том размере, какой он хочет Child.Arrange(new Rect(new Point(-childSize.Width/2, -childSize.Height/2), childSize)); // а сами занимаем ноль места return new Size(); } }
Имея такой декоратор, текстовую метку легко положить там, где нам хочется:

Получаем вот такой результат:

Что осталось сделать? Нужно отойти от заданной ширины в 200 пикселей, и разбросать код по UserControl'ам, чтобы избежать дублирования.
Для того, чтобы отойти от ширины, нужно воспользоваться скалированием. Хитрость состоит в том, что нельзя скалировать весь Path, потому что в этом случае пропорционально отскалируется и ширина границы. Скалировать нужно только геометрию:
M 0,-1 A 1,1 30 0 1 0.5,-0.86602 L 0.25,-0.43301 A 0.5,0.5 30 0 0 0,-0.5 z
Теперь скалирование можно задать через Binding
Следующая проблема — размер области. Нам нужен контрол, который сохраняет aspect ratio. Готового такого нет, но это будет полезная штука, так что засучим рукава и напишем его. (Поскольку контрол полезен сам по себе, я написал его более общим образом.)
public class AspectRatioDecorator : Decorator { #region dp double AspectRatio with validator ValidateAspectRatio public static readonly DependencyProperty AspectRatioProperty = DependencyProperty.Register( "AspectRatio", typeof(double), typeof(AspectRatioDecorator), new FrameworkPropertyMetadata( 1.0, FrameworkPropertyMetadataOptions.AffectsMeasure), ValidateAspectRatio);
public double AspectRatio { get { return (double)GetValue(AspectRatioProperty); } set { SetValue(AspectRatioProperty, value); } }
static bool ValidateAspectRatio(object value) { if (!(value is double)) return false;
var aspectRatio = (double)value; return aspectRatio > 0 && !double.IsInfinity(aspectRatio) && !double.IsNaN(aspectRatio); } #endregion
#region dp HorizontalAlignment HorizontalChildAlignment public HorizontalAlignment HorizontalChildAlignment { get { return (HorizontalAlignment)GetValue(HorizontalChildAlignmentProperty); } set { SetValue(HorizontalChildAlignmentProperty, value); } }
public static readonly DependencyProperty HorizontalChildAlignmentProperty = DependencyProperty.Register( "HorizontalChildAlignment", typeof(HorizontalAlignment), typeof(AspectRatioDecorator), new FrameworkPropertyMetadata( HorizontalAlignment.Center, FrameworkPropertyMetadataOptions.AffectsArrange), ValidateHorizontalChildAlignment);
static bool ValidateHorizontalChildAlignment(object value) { if (!(value is HorizontalAlignment)) return false;
var horizontalAlignment = (HorizontalAlignment)value; return horizontalAlignment != HorizontalAlignment.Stretch; } #endregion
#region dp VerticalAlignment VerticalChildAlignment public VerticalAlignment VerticalChildAlignment { get { return (VerticalAlignment)GetValue(VerticalChildAlignmentProperty); } set { SetValue(VerticalChildAlignmentProperty, value); } }
public static readonly DependencyProperty VerticalChildAlignmentProperty = DependencyProperty.Register( "VerticalChildAlignment", typeof(VerticalAlignment), typeof(AspectRatioDecorator), new FrameworkPropertyMetadata( VerticalAlignment.Top, FrameworkPropertyMetadataOptions.AffectsArrange), ValidateVerticalChildAlignment);
static bool ValidateVerticalChildAlignment(object value) { if (!(value is VerticalAlignment)) return false;
var verticalAlignment = (VerticalAlignment)value; return verticalAlignment != VerticalAlignment.Stretch; } #endregion
protected override Size MeasureOverride(Size constraint) { if (Child == null) // we have no child, so we need no space return new Size(0, 0);
constraint = SizeToRatio(constraint, false); Child.Measure(constraint);
if (double.IsInfinity(constraint.Width) || double.IsInfinity(constraint.Height)) return SizeToRatio(Child.DesiredSize, true);
return constraint; }
public Size SizeToRatio(Size size, bool expand) { double ratio = AspectRatio;
double height = size.Width / ratio; double width = size.Height * ratio;
if (expand) { width = Math.Max(width, size.Width); height = Math.Max(height, size.Height); } else { width = Math.Min(width, size.Width); height = Math.Min(height, size.Height); }
return new Size(width, height); }
protected override Size ArrangeOverride(Size arrangeSize) { if (Child == null) return arrangeSize;
var constrainedSize = arrangeSize;
var fwChild = Child as FrameworkElement; if (fwChild != null) { constrainedSize.Height = Math.Min(constrainedSize.Height, fwChild.MaxHeight); constrainedSize.Width = Math.Min(constrainedSize.Width, fwChild.MaxWidth); }
var newSize = SizeToRatio(constrainedSize, false);
double widthDelta = arrangeSize.Width - newSize.Width; double heightDelta = arrangeSize.Height - newSize.Height;
double top = 0; double left = 0;
if (!double.IsNaN(widthDelta) && !double.IsInfinity(widthDelta)) switch (HorizontalChildAlignment) { case HorizontalAlignment.Left: break; case HorizontalAlignment.Center: left = widthDelta / 2; break; case HorizontalAlignment.Right: left = widthDelta; break; };
if (!double.IsNaN(heightDelta) && !double.IsInfinity(heightDelta)) switch (VerticalChildAlignment) { case VerticalAlignment.Top: break; case VerticalAlignment.Center: top = heightDelta / 2; break; case VerticalAlignment.Bottom: top = heightDelta; break; };
var finalRect = new Rect(new Point(left, top), newSize); Child.Arrange(finalRect);
return arrangeSize; } }
Кроме того, чтобы забиндить размер без особенных трюков, нам нужен скалирующий IValueConverter
class ScalingConverter : IValueConverter { public object Convert( object value, Type targetType, object parameter, CultureInfo culture) { if (value == null || parameter == null) // поддержка редактора WPF return DependencyProperty.UnsetValue; double v = (double)value; double p = (double)parameter; return v * p; }
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture) { throw new NotSupportedException(); } }
Ну и для того, чтобы нормально передавать параметры в конвертер, сделаем типизирующий markup extension:
public class DoubleExtension : TypedValueExtension { public DoubleExtension(double value) : base(value) { } }
public class TypedValueExtension : MarkupExtension { public TypedValueExtension(T value) { Value = value; } public T Value { get; set; } public override object ProvideValue(IServiceProvider sp) { return Value; } }
Теперь можно написать так:
M 0,-1 A 1,1 30 0 1 0.5,-0.86602 L 0.25,-0.43301 A 0.5,0.5 30 0 0 0,-0.5 z M 0,-1 A 1,1 30 0 1 0.5,-0.86602 L 0.25,-0.43301 A 0.5,0.5 30 0 0 0,-0.5 z
Получаем следующую картинку:

Разбиение на UserControl'ы сделаете сами, хорошо?

Кодировка в Visual Studio, как включить utf-8?

Есть ли способ изменить кодировку файлов в Visual Studio на utf-8? Так, чтобы это было на постоянной основе. Нашел только один способ, но он меняет кодировку только одного файла из (к примеру) сотни уже имеющихся. Это
File -> Advanced Save Options и в списке Encoding выбрать UTF-8


Ответ

Для автоматического сохранения в UTF-8 всех новых файлов, содержащих символы, отличные от набора ASCII, необходимо включить опцию - Tools > Options > Environment > Documents > Save documents as Unicode when data cannot be saved in codepage

Как реализовать IComparer для сравнения нескольких свойств?

Положим, есть следуюший класс:
class Operation { public string Foo { get; set; } public string Bar { get; set; } public int Baz { get; set; } }
Я хочу реализовать компарер IComparer. Код получается такой:
class OperationComparer : IComparer { public int Compare(Operation x, Operation y) { if (x.Foo == y.Foo && x.Bar == y.Bar && x.Baz == y.Baz) return 0; else return 1; // ??? } }
Однако непонятно, что возвращать, если свойства не равны. Когда возвращать 1, а когда −1?


Ответ

Общий порядок написания компарера следующий:
Сравнить первое свойство, по которому происходит сравнение (сортировка), получив −1/0/1 (меньше/равно/больше). Если свойства не равны, вернуть −1 или 1 в соответствии с результатом сравнения. Для изменения порядка сортировки вернуть противоположное число. Если свойства равны, перейти к пункту 1 со следующим свойством. Если свойства кончились, вернуть результат последнего сравнения как есть.
Код получается следующий:
class OperationComparer : IComparer { public int Compare(Operation x, Operation y) { int cmp = string.Compare(x.Foo, y.Foo); if (cmp != 0) return cmp; cmp = string.Compare(x.Bar, y.Bar); if (cmp != 0) return cmp; cmp = x.Baz.CompareTo(x.Baz); return cmp; } }
Стоит отметить, что в современном коде подобные компареры обычно не нужны, так как есть LINQ, в котором с помощью методов OrderBy и ThenBy ту же логику можно выразить гораздо проще.

В каких случаях стоит выполнять проверку интернет соединения?

Пишу REST API приложение и при каждом запросе к серверу, сперва проверяю на наличие интернет соединения, и только в случае положительного результата, посылаю запрос на сервер.
Правильно ли я делаю? Или в каких случаях стоит выполнять проверку?


Ответ

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

Какой UnmanagedType соответствует UnicodeString из Delphi?

Delphi (UnicodeString):
function ShowDelphiMsg(inputStr : UnicodeString) : UnicodeString; stdcall; var a : UnicodeString; begin ShowMessage(inputStr); a := 'Тест!'; result := a; end;
C#
[DllImport("Native.dll", SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.LPWStr)] internal static extern string ShowDelphiMsg([MarshalAs(UnmanagedType.LPWStr)] string inputStr);
Такой вариант отлично передает из C# в Delphi строку, Delphi выводит строку. Но основная проблема - ошибка при возврате строки из Delphi.
Впорос: Какой UnmanagedType соответствует UnicodeString из Delphi?
p.s. архитектура у обоих приложений x64

Delphi (WideString):
function ShowDelphiMsg(inputStr : WideString) : WideString; stdcall; var a : WideString; begin ShowMessage(inputStr); a := 'Тест!'; result := a; end;
Так же вызывает ошибку при возврате значения.

Упростил функцию
C#:
[DllImport("Native.dll", SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.BStr)] internal static extern string ShowDelphiMsg();
Delphi:
function ShowDelphiMsg() : WideString; stdcall; var a : WideString; begin a := 'Тест!'; result := a; end;
Та же ошибка.


Ответ

Судя по коду UnmanagedType.LPWStr тут используется PWideChar, что есть указатель на WideString. Из функции возвращать надо именно WideString
UPD:
Оказывается, из-за особенностей C# (?) нужно использовать вот такой способ:
Delphi:
function SomeFunction2(out OutVar: Widestring): BOOL; stdcall; begin OutVar := 'Hello'; Result := True; end;
C#
[DllImport(@"Test.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool SomeFunction2([MarshalAs(UnmanagedType.BStr)] out string res);
т.е. возвращать WideString через результат нельзя, а вот делать out параметр (но не var см. ответ Alex) - запросто.
Нагуглено: https://stackoverflow.com/questions/9331026/why-can-delphi-dlls-use-widestring-without-using-sharemem

TaskScheduler и балансировка по ядрам для процессов

Как известно, TaskScheduler в TPL раскидывает таски по ядрам (хоть и не гарантирует это).
Возьмем другой случай - порождаются много копий процессов, где внутри поток с многочисленными Thread.Sleep. В таком варианте поток намертво прилипнет к какому то ядру.
Вопрос в том, если этот поток переделать на task-модель, то будут ли эти таски перемалываться на разных ядрах или же будут тяготеть к одному и тому же ядру? Хоть это и таски, но по факту один поток разбивается на таски, чтобы избежать sleep и TaskScheduler может тяготеть переиспользовать этот же поток (других то в пуле нет)


Ответ

Окей, вам нужно перебрасывать выполнение между ядрами. Это можно сделать вот как.
Подсчитываем количество ядер. Это легко: Environment.ProcessorCount Запускаем столько UI-потоков, сколько у нас ядер. Для этого берём код отсюда, и заимствуем из него класс DispatcherThread. Каждый из них представляет собой поток, в который можно переключиться при помощи await AsyncHelper.RedirectTo(t.Dispatcher); (оттуда же). Нам нужно разбросать эти потоки по ядрам. Это можно сделать как описано здесь Теперь в нашей async-функции, если мы хотим поменять ядро, просто пишем
currentCore = (currentCore + 1) % Environment.ProcessorCount; await AsyncHelper.RedirectTo(threads[currentCore].Dispatcher);

Полный код:
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Threading;
namespace SO5 { class Program { static List threads; static int currentCoreNo = 0;
static void Main(string[] args) { threads = Enumerable.Range(0, Environment.ProcessorCount) .Select(coreNo => new CoreAffineDispatcherThread(coreNo)) .ToList(); Run().Wait();
foreach (var t in threads) t.Dispose(); }
static async Task Run() { for (int i = 0; i < 10; i++) { await Task.Delay(100);
currentCoreNo = (currentCoreNo + 1) % Environment.ProcessorCount; await AsyncHelper.RedirectTo(threads[currentCoreNo].Dispatcher);
var t = Thread.CurrentThread; Console.WriteLine($"Task reporting from thread {t.ManagedThreadId}," + $" thread pool: {t.IsThreadPoolThread}"); } }
public class CoreAffineDispatcherThread : IDisposable { public Dispatcher Dispatcher { get; private set; }
Thread thread;
public CoreAffineDispatcherThread(int coreNumber) { using (var barrier = new AutoResetEvent(false)) { thread = new Thread(() => { Dispatcher = Dispatcher.CurrentDispatcher; barrier.Set(); Thread.BeginThreadAffinity();
#pragma warning disable 618 // The call to BeginThreadAffinity guarantees stable results // for GetCurrentThreadId, so we ignore the obsolete warning int osThreadId = AppDomain.GetCurrentThreadId(); #pragma warning restore 618
// Find the ProcessThread for this thread. ProcessThread thread = Process.GetCurrentProcess() .Threads.Cast() .Where(t => t.Id == osThreadId) .Single(); // Set the thread's processor affinity var cpuMask = 1 << coreNumber; thread.ProcessorAffinity = new IntPtr(cpuMask);
Dispatcher.Run();
Thread.EndThreadAffinity(); });
thread.SetApartmentState(ApartmentState.STA); thread.Start(); barrier.WaitOne(); } }
public void Dispose() { Dispatcher.InvokeShutdown(); if (thread != Thread.CurrentThread) thread.Join(); } } }
static class AsyncHelper { public static DispatcherRedirector RedirectTo(Dispatcher d) { return new DispatcherRedirector(d); } }
public struct DispatcherRedirector : INotifyCompletion { public DispatcherRedirector(Dispatcher dispatcher) { this.dispatcher = dispatcher; }
#region awaiter public DispatcherRedirector GetAwaiter() { // combined awaiter and awaitable return this; } #endregion
#region awaitable public bool IsCompleted { get { // true means execute continuation inline return dispatcher.CheckAccess(); } }
public void OnCompleted(Action continuation) { dispatcher.BeginInvoke(continuation); }
public void GetResult() { } #endregion
Dispatcher dispatcher; } }
При тестовом пробеге выдаёт:
Task reporting from thread 10, thread pool: False Task reporting from thread 11, thread pool: False Task reporting from thread 12, thread pool: False Task reporting from thread 13, thread pool: False Task reporting from thread 14, thread pool: False Task reporting from thread 15, thread pool: False Task reporting from thread 16, thread pool: False Task reporting from thread 9, thread pool: False Task reporting from thread 10, thread pool: False Task reporting from thread 11, thread pool: False