• Как разрабатывать ПО с GUI, который адаптируется под определённого пользователя?

    WNeZRoS
    @WNeZRoS
    использовать условные конструкции для решения об отображении или неотображении тех или иных элементов GUI, либо иметь разные XAML-формы для разных групп пользователей


    Это одно и тоже решение, просто условия разное меняют. Всё зависит от вида приложения можно применять разные решения.

    Для хороших WPF приложений принято использовать MVVM, соответственно для всего будут вьюмодели.
    Если это приложение - набор ярлыков, то можно просто не создавать вью модели или скрывать (BooleanToVisibilityConverter) недоступные ярлыки.
    Если что-то сложнее, то вероятно для разных пользователей будут разные вьюмодели и разные XAML шаблоны для них.
    Ответ написан
    Комментировать
  • Почему двумерные массивы работают чуть быстрее одновременых?

    WNeZRoS
    @WNeZRoS
    // [][] 4865
    // [,]  5192
    // []   4852


    int[] - простейший массив, в памяти лежит линейно.
    Работает за счёт IL инструкций (newarr, ldelem, ...), которые могут лучше оптимизировать jit компилятором

    int[,] - многомерный массив, в памяти лежит также линейно как int[].
    Работает через вызовы методов, а так же за счёт не популярности работает на общем коде с массивами где первый элемент может быть не по индексу 0. Соответственно, для доставания элементов требуется дополнительная математика и проверки.

    int[][] - массив массивов, в памяти линейно лежат ссылки на линейно лежащие строки.
    Работает медленнее int[] потому что требуется доступ к другим участкам памяти (строкам).
    Ответ написан
    Комментировать
  • Как виртуальные машины исполняют код и как правильно это реализовать?

    WNeZRoS
    @WNeZRoS
    Если вопрос при виртуальные машины по типу тех что используется для исполнения Java или C# кода, то инструкции в них гораздо проще. В CIL например, у большинства инструкций нет параметров, они просто берут нужные данные с конца стека. А когда параметры есть - он один: значение или токен переменной/функции.

    Можно посмотреть как C# преобразуется в инструкции виртуальной машины на sharplab.io, сопоставить и понять как оно выполняется.

    Например
    IL_0000: ldarg 1 // кладёт в стек первый аргумент
    IL_0001: ldarg 2 // кладёт в стек второй аргумент
    IL_0002: sub     // достаёт из стека два последних значения и отнимает последний от пред последнего (т.е. будет arg.2 - arg.1), результат складывается в стек
    IL_0003: brtrue.s IL_0011 // достаёт из стека значение, если оно не 0, переходит к инструкции IL_0011, если 0 исполнения идёт дальше на I_0005
    
    IL_0005: ldstr "zero" // загружает в стек строку "zero"
    IL_000a: call void System.Console::WriteLine(string) // вызывает вывод в консоль, из стека достаются N нужных значений для параметров (в данном случае 1), void функция ничего в стек не добавляет
    IL_000f: br.s IL_001b // переход (jump) к IL_001b
    
    IL_0011: ldstr "not zero" // загружает в стек строку "not zero"
    IL_0016: call void System.Console::WriteLine(string) // вызывает вывод в консоль, из стека достаётся 1 значения для параметра 
    
    IL_001b: ldstr "done" // загружает в стек строку ...
    IL_0020: call void System.Console::WriteLine(string) // ...


    Пример реализации простой виртуальной машины на основе примера выше

    (Код написан так чтобы работал, правильнее писать более безопасно и читабельнее)

    #include <stdio.h>
    
    enum Opcode {
        OP_LOAD_ARGUMENT,
        OP_LOAD_STRING,
        OP_SUBTRACT,
        OP_GOTO,
        OP_GOTO_IF_TRUE,
        OP_CALL,
        OP_RETURN
    };
    
    union Argument {
        int value;
        const void* pointer;
    };
    
    struct Instruction { 
        Opcode opcode; 
        Argument arg; 
    };
    
    void run_vm(const Instruction* instructions, const Argument* args) {
        Argument stack[16];
        
        Argument* stack_pointer = &stack[0];
        int address = 0;
    
        while(true) {
            const Instruction instruction = instructions[address];
            address++;
    
            switch(instruction.opcode) {
                case OP_RETURN:
                    return;
                
                case OP_LOAD_ARGUMENT:
                    *stack_pointer = args[instruction.arg.value];
                    stack_pointer++;
                    break;
    
                case OP_LOAD_STRING:
                    *stack_pointer = instruction.arg;
                    stack_pointer++;
                    break;
    
                case OP_SUBTRACT:
                {
                    stack_pointer--;
                    int b = stack_pointer->value;
                    
                    stack_pointer--;
                    int a = stack_pointer->value;
    
                    stack_pointer->value = a - b;
                    stack_pointer++;
                    break;
                }
    
                case OP_GOTO:
                    address = instruction.arg.value;
                    break;
    
                case OP_GOTO_IF_TRUE:
                    stack_pointer--;
                    if(stack_pointer->value != 0)
                        address = instruction.arg.value;
                    break;
    
                case OP_CALL:
                    void (* fn)(const void*) = (void (*)(const void*))instruction.arg.pointer;
                    stack_pointer--;
                    fn(stack_pointer->pointer);
                    break;
            }
        }
    }
    
    void print(const char* text) { printf("%s\n", text); }
    
    int main(int argc, char** argv) {
        const Instruction instructions[] = {
            /* 0 */ { OP_LOAD_ARGUMENT, { 0 } },
            /* 1 */ { OP_LOAD_ARGUMENT, { 1 } },
            /* 2 */ { OP_SUBTRACT, {} },
            /* 3 */ { OP_GOTO_IF_TRUE, { 0x7 } },
            /* 4 */ { OP_LOAD_STRING, { .pointer = "zero" } },
            /* 5 */ { OP_CALL, { .pointer = (void*)&print } }, // функции надо где-то регистрировать, чтобы знать сколько у них параметров и какого они типа
            /* 6 */ { OP_GOTO, { 0x9 } },
            /* 7 */ { OP_LOAD_STRING, { .pointer = "not zero" } },
            /* 8 */ { OP_CALL, { .pointer = (void*)&print } },
            /* 9 */ { OP_LOAD_STRING, { .pointer = "done" } },
            /* A */ { OP_CALL, { .pointer = (void*)&print } },
            /* B */ { OP_RETURN, {} }
        };
    
        const Argument args[] = { 
            { 100500 },
            { 777 }
         };
    
        run_vm(instructions, args);
        return 0;
    }



    Виртуальные машины для процессоров можно делать по такому же принципу, но они будут медленные и структура инструкций ограничена архитектурой процессора.
    Ответ написан
    Комментировать
  • Как блок питания определяет выходное напряжение?

    WNeZRoS
    @WNeZRoS
    При помощи USB Power Delivery
    Ответ написан
    Комментировать
  • Как получить последние 3 символа строки используя Lambda expression?

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

    string n2string = "sdfihsdfguhdsfo[ghdfhgdsfhghdfsgdfhghdsfg9wh328932u82hbsab zb cx9832u83232hbnibcz";
    int countMinus3 = n2string.Length - 3;
    
    {
        string lastThreeSymbols = n2string.Substring(countMinus3);
        Console.WriteLine($"lastThreeSymbols = {lastThreeSymbols}");
    }
    {
        string lastThreeSymbols = string.Concat(n2string.Where((_, i) => i >= countMinus3));
        Console.WriteLine($"lastThreeSymbols = {lastThreeSymbols}");
    }
    {
        string lastThreeSymbols = n2string.Where((_, i) => i >= countMinus3).Aggregate(string.Empty, (s, c) => s + c);
        Console.WriteLine($"lastThreeSymbols = {lastThreeSymbols}");
    }
    {
        string lastThreeSymbols = n2string.Aggregate(string.Empty, (s, c) => (s.Length > 2 ? s.Substring(1) : s) + c);
        Console.WriteLine($"lastThreeSymbols = {lastThreeSymbols}");
    }
    Ответ написан
  • Какие есть решения для создания чертежа/развёртки из 3D модели созданной на основе другой модели?

    WNeZRoS
    @WNeZRoS
    У Blender есть встроенный аддон Paper Model для генерации схемы бумажной модели, возможно и для обёртки подойдёт.
    https://docs.blender.org/manual/en/latest/addons/i...
    Ответ написан
    Комментировать
  • Как можно сделать перебор по массиву быстрее?

    WNeZRoS
    @WNeZRoS
    Если было бы больше контекста, то можно было бы что-то увереннее советовать. По этому куску кода можно дать только такие комментарии (считая что Get* методы и итераторы не имеют сайд эффектов):
    var someItems = _someService.GetList();
    foreach (var item in someItems) // item внутри не используется, можно убрать этот foreach
    {
        var additionalItems = _additionItemsSerivce.GetList();
        foreach (var additionalItem in additionalItems)
        {
            var properties = additionalItem.Properties;
            foreach (var property in properties)
            {
                property.First = true;
                property.First = true; // зачем делать одно и тоже два раза?
                _additionItemsSerivce.UpdateProperies(additionalItem); // property не используется, значит можно вынести за этот foreach
            }
        }
    }


    Если по этим комментариям убрать лишнее, получится что-то такое:
    var additionalItems = _additionItemsSerivce.GetList();
    foreach (var additionalItem in additionalItems)
    {
        var properties = additionalItem.Properties;
        foreach (var property in properties)
            property.First = true;
        
        _additionItemsSerivce.UpdateProperies(additionalItem);
    }


    Так же странно что все проперти у вас получают флаг First, возможно вместо foreach по properties стоит получить только первый элемент и ему установить First = true.
    Ответ написан
    Комментировать
  • Как исправить ошибку "- Подпись кода: «apksigner» завершился с ошибкой #1" в Godot при экспорте проекта на Android?

    WNeZRoS
    @WNeZRoS
    Судя по таким же сообщениям на формах и баг трекере, проблема скорее всего в том что Godot использует build tools не той версии (скорее всего нужной версии вообще не установлено).

    Чтобы всё работала нужно установить всё именно тех версий что указана в документации к вашей версии Godot (для 3.6 - 30.0.3, для 4.0 - 33.0.2).
    Ответ написан
  • Куда можно выложить свою первую игру на Unity?

    WNeZRoS
    @WNeZRoS
    itch.io — онлайн-сервис для размещения, продажи и загрузки инди-игр. Сервис запущен в марте 2013 года и на апрель 2021 года насчитывает более 200 тысяч игр.

    Выложить можно любую игру, но шансов что её скачают больше 10 человек за месяц без дополнительного распространения не много. Чтобы точно нашлись люди поигравшие в игру, и, возможно, даже оставившие отзыв, можно участвовать в геймджемах на том же itch.io.
    Ответ написан
    1 комментарий
  • Unity выдаёт ошибку: 'slenderAI' does not contain a definition for 'position'. Я не понимаю почему, объясните?

    WNeZRoS
    @WNeZRoS
    В указанной строке затесалось this.position.y вместо player.position.y
    Ответ написан
    1 комментарий
  • Как сделать прозрачный фон png фото wpf?

    WNeZRoS
    @WNeZRoS
    Чтобы был прозрачный фон у png в wpf, нужно чтобы у самой png фон был прозрачный, а не серо-белая клеточка.
    Ответ написан
    Комментировать
  • Как загрузить нод на сцену в Godot Mono?

    WNeZRoS
    @WNeZRoS
    $"..." - синтаксический сахар для get_node("...").

    В C# это так будет:
    private Node node;
    
    public override void _Ready()
    {
        node = GetNode<Node>("../Node");
    }
    Ответ написан
    1 комментарий
  • Dotnet использует msbuild для сборки?

    WNeZRoS
    @WNeZRoS
    Да, использует. Можно даже вызывать msbuild через dotnet: dotnet.exe msbuild ...
    Ответ написан
    Комментировать
  • Почему код завершается с кодом 0?

    WNeZRoS
    @WNeZRoS
    Код завершения процесса 0 - стандартный код обозначающий что всё завершилось без критичных проблем (т.е. успешно, хороошо).
    На скриншотах никаких ошибок нет, только сообщения от дебаггера о загрузке стандартный dll файлов и завершении потоков.
    Ответ написан
    Комментировать
  • Не освобождается поток или другая причина недоступности файла?

    WNeZRoS
    @WNeZRoS
    Вот так выглядит File.OpenRead:
    public static FileStream OpenRead(string path)
    {
       return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
    }

    А так конструктор с двумя параметрами для FileStream:
    internal const FileShare DefaultShare = FileShare.Read;
    
    public FileStream(string path, FileMode mode)
        : this(path, mode, mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite, DefaultShare, DefaultBufferSize, DefaultIsAsync) {}


    Собственно главная разница в переданном FileAccess. В случае OpenRead файл открывается только для чтения, а в случае FileStream и на чтение и на запись. Переданный FileShare позволяет только читать файл из нескольких мест, и при открытии с FileAccess.ReadWrite как раз получается ваша проблема (т.к. оно хочет ещё и писать в файл).
    Ответ написан
    Комментировать
  • Как преобразовать тип ReadOnlySpan?

    WNeZRoS
    @WNeZRoS
    Из ReadOnlySpan<byte> можно распарсить число при помощи System.Buffers.Text.Utf8Parser.TryParse
    Пример использования можно увидеть в этой статье.
    Ответ написан
    Комментировать
  • Как найти ближайшее подобное соотношение чисел с целым результатом?

    WNeZRoS
    @WNeZRoS
    При вычислении нужной ширины для 4:3 дробь получается потому что 400 на 3 не делится нацело.
    Соответственно, чтобы найти целое число, надо найти ближайшее к 400 число которое делится на 3. Оно может быть меньше (399) или больше (402), зависит от ваших нужд. Искать можно перебором, или математикой - остатком от деления.
    Ответ написан
  • Как использовать ноутбук как монитор?

    WNeZRoS
    @WNeZRoS
    В Windows 11 есть приложение "Беспроводной дисплей", который может получать картинку по Miracast, но работает очень не стабильно и медленно. Есть и другие реализации, можно найти запросом "Miracast Server", их в деле не видел.
    Проводной вариант можно реализовать с помощью карты захвата HDMI, которая будет подключена к ноутбуку и через какое-то приложение показывать во весь экран что там захватилось.
    Но все эти варианты относительно прямого подключения к монитору будут иметь дополнительную задержку, и, возможно, потерю качества картинки.
    Ответ написан
    Комментировать
  • Как реализовать одновременное присваивание и ввод чисел через пробел?

    WNeZRoS
    @WNeZRoS
    Можно сделать так же как в Python:
    var (a, b) = Console.ReadLine().Split(" ").Select(int.Parse);


    но надо добавить метод деконструкции IEnumerable на 2 элемента:
    public static class DeconstructEnumerable
    {
    	public static void Deconstruct<T>(this System.Collections.Generic.IEnumerable<T> enumerable, out T item1, out T item2)
    	{
    		using var enumerator = enumerable.GetEnumerator();
    		if (!enumerator.MoveNext())
    			throw new ArgumentException("not enough values to unpack (expected 2, got 0)", nameof(enumerable));
    										
    		item1 = enumerator.Current;
    										
    		if (!enumerator.MoveNext())
    			throw new ArgumentException("not enough values to unpack (expected 2, got 1)", nameof(enumerable));
    		
    		item2 = enumerator.Current;
    		
    		if (enumerator.MoveNext())
    			throw new ArgumentException("too many values to unpack (expected 2)", nameof(enumerable));
    	}
    }
    Ответ написан
    1 комментарий
  • Почему получаю False при сравнение 2-х одинаковых строк?

    WNeZRoS
    @WNeZRoS
    Всегда можно написать функцию для поиска разницы:
    (int, char, char) FindFirstDifference(string a, string b)
    {
        var length = Math.Min(a.Length, b.Length);
        for (int i = 0; i < length; i++) 
        {
            if (a[i] != b[i])
                return (i, a[i], b[i]);
        }
    
        if (a.Length == b.Length)
            return (-1, '\0', '\0');
    
        return (length, a.Length == length ? '\0' : a[length], b.Length == length ? '\0' : b[length]);
    }


    В теории могут быть визуально похожие unicode символы, но в вашем случае они просто разные.
    Ответ написан
    Комментировать