Страницы

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

среда, 5 июня 2019 г.

Создание ПО с плагинами

По долгу службы требуется реализация довольно сложного десктопного ПО. Как одно из требований — плагины (подключаемые модули), которые могут быть очень разнообразными: от определения новых типов данных до работы с интерфейсом (добавление форм, кнопок и т.п.). Разумеется, также требуются аналитика, обработка данных, сохранение в разные БД и т.д.
Платформы для выбора — C# или Delphi (т.к. есть прототип, реализующий 90% потребного функционала, но в режиме «спагетти»).
Если с Delphi всё понятно — средство загрузки/выгрузки плагинов делать руками, то вот с C# не всё так прозрачно.
Пока что быстрый поиск показал следующие варианты:
MEF: довольно просто в реализации, но нельзя изолировать плагины в отдельных AppDomain (что довольно-таки важно, это существенное архитектурное преимущество .NET вообще и шарпа в частности); MAF: переусложнено, замудрённо, и, с виду, уже не поддерживается. С другой стороны — мощная изоляция; самостоятельная реализация на reflection (например, так), с возможностью загрузки в AppDomain и прочим. Но придётся много велосипедить, чего в общем-то не хочется.
Есть ещё варианты? Может, что-то не было учтено?
UPD: добавил ссылки.


Ответ

Для C# есть встроенное готовое решение от Microsoft: System.Addin. Позволяет конфигурировать плагины так, чтобы использовать их в том же AppDomain'е, или в выделенном другом, или каждый в своём, или вообще в отдельном процессе.
Не понимаю, почему везде советуют MEF. Это решение именно для расширяемости: код, который вы загружаете, считается доверенным и очень мало отличается от основного кода приложения, поэтому возможности выгрузки и управление правами напрочь отсутствуют.
Самостоятельный велосипед на reflection написать можно, но придётся довольно серьёзно разбираться в тонкостях наподобие Fusion и Load context, так что я бы не советовал тратить время.

Обновление: Ага, System.Addin — это то, что вы называете MAF.

Как распараллелить вложенные циклы с помощью Stream

Познавая Java 8 открыл для себя стримы. Решил попробовать распараллелить достаточно долгие вложенные циклы, но столкнулся с проблемой - пока не знаю как.
Вот так выглядит последовательный код:
long total = 0; BitVector vector = getVector(); // из библиотеки import cern.colt.bitvector.* for (int index = 0; index < vector.size(); index++){ if (vector.get(index)){ for (TrafficData trafficData : trafficDataList){
int visitorTrafficDataIndex = getVisitorTrafficDataIndex(index, trafficData);
if (visitorTrafficDataIndex >= 0){ totalTrafficImpressions += (long)(trafficData.getVolume()[visitorTrafficDataIndex]); } } } }
Думал сделать что-то типа такого:
long total = IntStream.range(0, vector.size()).parallel() .filter(index -> vector.get(index)) .mapToLong(index -> trafficDataList.stream() .map(trafficData -> getVisitorTrafficDataIndex(index, trafficData)) .filter(visitorTrafficDataIndex -> visitorTrafficDataIndex >= 0) .mapToLong(visitorTrafficDataIndex -> (long)(trafficData.getVolume()[visitorTrafficDataIndex]) // здесь уже нет объекта использовать trafficData .sum()) ).sum();
Проблема в том, что не компилируется..


Ответ

Если я правильно понял вашу проблему, то надо делать как-то так:
long total = IntStream.range( 0, vector.size() ).parallel().filter( index -> vector.get( index ) ) .mapToLong( index -> trafficDataList.stream().parallel().map( trafficData -> { int visitorTrafficDataIndex = getVisitorTrafficDataIndex( index, trafficData ); if (visitorTrafficDataIndex >= 0) { return trafficData.getVolume()[visitorTrafficDataIndex]; } return 0; } ).sum() ).sum();
Сделать так как хотите вы (всё на стримах) не получится, потому что после того как вы map(trafficData -> getVisitorTrafficDataIndex(index, trafficData)) в вашем стриме уже нет объекта trafficData, он(стрим) уже просто коллекция int.

Как узнать каким пользователем занят файл в сети?

Есть сетевой .xls-файл.
Как можно программно узнать, каким пользователем занят данный файл?


Ответ

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

Диакритические знаки в итальянском алфавите

В итальянском алфавите есть буквы с диакритическими знаками: à, è, é, ì, í, î, ò, ó, ù, ú
На входе строка, которая может содержать такие знаки, а может и не содержать.
Вопрос: Как лучше заменить их на привычную латиницу (т.е. 'à'=>'a', 'è'=>'e' и т.д.), не перебирая каждый знак?


Ответ

$str = "à, è, é, ì, í, î, ò, ó, ù, ú"; echo iconv('utf-8', 'us-ascii//TRANSLIT', $str);

Android, SQLite, создание базы данных

Я немного не понимаю. При вызове (а точнее создании базы данных), разве не должен вызываться метод onCreate? Вот код базы данных:
public class DBHelper extends SQLiteOpenHelper { String name; final String TAG = "APP"; final String MSG = "БАЗА ДАННЫХ: ";
public DBHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, 1); }
public DBHelper(Context context, String name) { super(context, name, null, 1); this.name = name; }
@Override public void onCreate(SQLiteDatabase db) { Log.i(TAG, MSG + "создание таблицы " + name);
if (name.equals("dictionaries")) { db.execSQL("create table " + name + " (" + BaseColumns._ID + " integer primary key autoincrement, " + "dictionary" + " String);"); } else { Log.i(TAG, MSG + "создание таблицы 1"); db.execSQL("create table " + name + "_verb" + " (" + BaseColumns._ID + " integer primary key autoincrement, " + "last" + " String, " + "currently" + " String, " + "next" + " String, " + "translate + String);"); Log.i(TAG, MSG + "создание таблицы 2"); db.execSQL("create table " + name + "_noun" + " (" + BaseColumns._ID + " integer primary key autoincrement, " + "word" + " String, " + "translate" + " String);"); Log.i(TAG, MSG + "создание таблицы 3"); db.execSQL("create table " + name + "_phrase" + " (" + BaseColumns._ID + " integer primary key autoincrement, " + "phrase" + " String, " + "translate" + " String);"); } }
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
После вызова несуществующей таблицы, в лог выводит сообщение только из конструктора DBHelper, а метод не запускается. Это нормально или так не должно быть?


Ответ

Согласно тык и тык
Проблема здесь в том, что в конструкторе вы явно не вызываете метод onCreate() и в конструкторе супер-класса этого вызова тоже нет. Чтобы его вызвать вы можете просто в коде вызвать методы получения объекта БД и она будет создана, если ещё не создана (т.е. будет вызван метод onCreate())
DBHelper dBHelper = new DBHelper(getContext()); dBHelper.getWritableDatabase(); //или //dBHelper.getReadableDatabase();

Удаление класса у элемента

Почему не получается удалить класс внутри

  • ?
    $('.js-btn').on('click', function(e) { e.preventDefault(); $('.triger.active').parent('li.list').removeclass('active'); }); .active { color: red; } click


    Ответ

    removeclass -> removeClass и если надо удалить у ссылки, то parent не нужен
    $('.js-btn').on('click', function(e) { e.preventDefault(); $('.list .triger.active').removeClass('active'); });

  • Почему нельзя 2 + + ++3?

    В этом ответе разобрались, что 2 + + 3 читается компилятором как 2 + (+3), то есть второй плюс — унарный.
    В таком случае, почему не работает такое?
    2 + + ++3
    Как бы я это понимал, будучи компилятором:
    2 + ( +( ++3 ) )
    ( ++3 ) — выполнить инкремент и вернуть значение 4 ( +4 ) — унарный плюс к 4, вернуть 4 2 + 4, сложение, вернуть 6
    Где ошибка в моем внутреннем компиляторе Java?
    Кстати, 2 + + 3++ тоже не работает.


    Ответ

    Сам понял! Потому что инкременты нельзя применять к константам. Такое работает:
    int a = 2; int b = 3; System.out.println(+ a++ + + ++b);