Задать вопрос
Ответы пользователя по тегу C#
  • Как загнать в dictionary key как null?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    Условный оператор в возвращаемом выражении в лямбде в GroupBy формально имеет тип результата int?, и у ситаксического анализатора при выводе типа возвращаемого значения не хватило то ли мозгов догадаться, что результат не может быть null, то ли полномочий изменить тип возвращаемого выражения на int.
    Упростите ему задачу: используйте операцию объединения с null (?? - null-coalescing), тип ее результата гарантированно не-nullable:
    asd.Value?.GroupBy(x => x.ParentId??0 ).ToDictionary(gg => gg.Key, gg => gg.ToList());
    Ответ написан
    Комментировать
  • Как ограничить количество запросов на сервер при создании поисковика?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    Не то, чтобы ответ, но идея ответа. И если чо непонятно - могу в каментах поуточнять.
    Со стороны тыла (на C#) можно ограничить число параллельных запросов в целом к сервису безо всяких там плагинов, а саморучно сделанным велосипедом: семафором (например, SemaphoreSlim, как самым модным в этом сезоне). Либо сделать его статическим, либо (чтобы веру в IoC свято блюсти и модульные тесты делать) - запихнув в Singleton-сервис с теми же свойствами/методами, что и у семафора используются, и получать этот сервис через конструктор (передавать через DI - в бою, напрямую - в тесте).
    Для семафора(сервиса) устанавливаете максимальное число параллельно выполняемых запросов в качестве начального значения. При входе в обработчик захватываете семафор (Wait/WaitAsync, таймаут - по вкусу), при выходе (лучше - в блоке finally того try, который начинается после захвата семафора) - освобождаете (Release).
    Таймаут выставляете в зависимости от поведения фронта: какие у него у самого таймауты на запрос (в том числе - на повторение) и как он реагирует на задержку ответа и на всякие разные коды статуса HTTP в ответе. В целом, стратегии тут две. Первая - пытаться захватывать семафор с коротким таймаутом и в случае неудачи - возвращать другой код статуса, кроме ОК, чтобы сказать фронту, что он не прав. Вторая - тормозить лишние запросы таймаутами. Кароче, без знания вашего фронтового плагина тут точно не скажешь, а я его знать не знаю и знать не хочу.
    Ответ написан
    Комментировать
  • Почему метод Cancel() объекта cancelTokenSource действует и на объект Task, которому в параметры конструктора токен не передаётся (см. внутри)?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    CancellationToken, передаваемый коструктору Task, не имеет никакого отношения к делегату, составляющему тело задачи (у вас им является ваша лямбда-функция). Он служит для отмены самой задачи, пока она ещё не запущена на выполнение. А делегат тела задачи даже не может просто взять и обратиться к этому CancellationToken. И, чтобы делегат мог с ним работать, этот CancellationToken надо передать делегату каким-то другим образом.
    Вы передаете этот CancellationToken через замыкание лямбда-функции (это умное слово означает, что вы просто сослались в ней на эту переменную). Причем, вы его передаете в тело и той, и другой задачи, через одну и ту же переменную token. Именно поэтому при вызове Cancel() для источника этого CancellationToken (cancelTokenSource) обе задачи обнаруживают этот факт и прекращают свое выполнение.
    PS Если интересует, где про это прочитать побольше, то - в книге Дж.Рихтера "Программирование на платформе Microsoft .NET Framework 4.5 на языке Csharp, CLR via Csharp" в гл.27 (в более новом издании, если такое есть, номер главы может измениться).
    Ответ написан
    2 комментария
  • Как должен быть путь для контроллера?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    Если вы, как у вас написано, передаете название страны и города через путь в URL, то параметры метода Action для URL второго формата должен привязываться к переменной маршрутизации, примерно так:
    [HttpGet("{country}/{city}")]
    public IActionResult ActionMethod([FromRoute] String country, [FromRoute] String city) 
    {
      //... method code
    }

    [FromRoute] можно и не писать, если параметров запроса (то, что после '?' в URL) нет: привязка по умолчанию выберет следующим источником переменные маршрутизации.
    PS Можно обойтись одним методом действия (Action), если указать что city - параметр необязательный
    [HttpGet("{country}/{city?}")]
    public IActionResult ActionMethod([FromRoute] String country, [FromRoute] String? city) 
    {
     if(city==null) {
      //... method 1 code 
     }
     else {
      //... method 2 code 
     }
    }
    Ответ написан
    Комментировать
  • Как вызвать поток дважды поочерёдно?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    Поток повторно запустить нельзя. После th1.join() (этот вызов дожидается завершения потока) cоздайте новый поток, присвойте его нужной переменой - да хоть той же th1 - и запустите его: будет функциональный аналог Task.ContinueWith(). Или же запустите th2, который у вас уже создан, но не запущен.
    Если вы хотите сделать два вызова Print в одном потоке - сделайте. Если между первым и вторым вызовом надо выполнить какой-нибудь код в основном потоке, то придется использовать объекты синхронизации, в данном случае - события, и ждать на них. Про это курите тему ManualResetEvent/AutoResetEvent, в двух словах в ответе всю эту тему не объяснить
    Ответ написан
    Комментировать
  • Где ошибка, как из рекурсии цикл сделать?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    //...declarations and initializations omitted
               do
               {
                   //...some code omitted
                   if (j != i)
                   {
                       swap(i, j);
                       i = j; 
                   }
               } while (j != i);

    Не работает, потому что вы сначала присваете j значение i, если они не равны, а потом, в условии продолжения цикла, сравниваете их значения. Естественно, они будут равны и выход их цикла получится на первой же итерации. Проверять i==j как условие выхода из цикла надо чуть раньше, например, так:
    //...declarations and initializations omitted
               do
               {
                   //...some code omitted
                   if (j != i)
                   {
                       swap(i, j);
                       i = j; 
                   }
                   else break;
               } while (true);


    Ну, а что до второго вопроса, то в .NET, начиная с 6.0 есть класс System.Collections.Generic.PriorityQueue<TElement,...
    Ответ написан
    6 комментариев
  • Какой должна быть архитектура веб-сервиса работающего одновременно с мобильным приложением и с браузером?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    1. Сразу насчет микросервисов: оно, конечно, стильно-модно-модожежно, но для начала ознакомьтесь со свежим переводом недавней статьи на Хабре "Смерть от тысячи микросервисов" и задумайтесь: а у вас там точно требуется такой уровень гибкости, масштабирования и т.п., что без микросервисов никак. Задуматься стоит IMHO - выбор неоднозначный, и за вас его никто не сделает.
    2. Если вы знакомы с MVC и кго контроллерами, то вам будет несложно писать контролеры API на ASP.NET Core в старом добром стиле: традиционно они тоже базируются на инфраструктуре MVC. Там почти та же логика привязки параметров: ну, разве что, там стало автоматическим преобразование объектов на JSON из тела запроса в параметр-объект, но, вроде бы, можно использовать и старый стиль с несколькими параметрами с привязкой их одноименным свойствам объекта. Там используется та же самая маршрутизация по атрибутам - она должна быть вам знакома, если только вы не застряли в legacy времен MVC Framework 4, где была только центральная маршрутизация. Ну а возвращаемые объекты ASP.NET Core сам автоматически преобразует в JSON.
    Правда, начиная с ASP.NET 6 появился (а начиная с ASP.NET 7 стал нормально документированым) альтернативный вариант создания API - Minimal API, но раз у вас есть опыт работы с MVC, то наверное, вам лучше остаться с этим старым добрым вариантом.
    Насчет формата обмена - вызовов и результатов API - у вас полная свобода, но имейте в виду, что при использовании REST вы получите автоматизированню поддержку описания этих форматов через OpenAPI/Swagger: фронтовики с мобильщиками это оценят.
    Делать ли генерацию HTML для браузера на веб-сервере через View по шаблонам Razor или же поручить эту работу фронтовикам, снабжая их данными через API - это предмет выбора, это зависит: как там у вас с квалификацией фронтовых разработчиков, как с требованиями к интерактивности страницы в браузере (MVC этому не способствует, костыли для подключения фронтовых фреймворков у MS, вроде как, есть, но я за них ничего не скажу - не пользовался), не придется ли по соображениям производительности переходить к Server Side Rendering (View - они как раз про это, а если изначально HTML генирился на фронте то перенести его в ASP.NET будет сложно) и т.п.
    Авторизацация в ASP.NET Core есть из коробки, самых разных видов: часть уже встроена, для части придется подключать сторонние NuGet-пакеты, но подробности я вам тут не опишу.
    А в общем совет у меня такой: собирайте информацию и думайте сами, а попытки копировать "как у других" - они могут привести к совершенно неожиданным результатам: каждая задача в чем-то уникальна.
    Ответ написан
    Комментировать
  • Как пройтись циклом по результирующим данным функции?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    Естественно не можете, потому что ServiceResult у вас IEnumerable не реализует (про это написано в сообщении об ошибке). А IEnumerable, по которому можно пройтись - это параметр-тип для ServiceResult, и до значения этого типа еще надо добраться.
    Разберитесь, что это у вас за обобщенный тип - ServiceResult (похоже, это из какой-то сторонней библиотеки), найдите в нем свойство типа T (или метод, возвращающий T) - который тип T в вашем случае - это IEnumerable - и пройдитесь циклом foreach по значению этого свойства (или результату, возвращенному методом).
    PS Если не найдете - дайте больше информации по используемым библиотекам (пакетам NuGet и т.п.), иначе придется вам ждать телепатов или ясновидящих, чтобы они эту информацию нам передали.
    Ответ написан
    Комментировать
  • Есть ли смысл завершать задачи генерируя ошибку(token.ThrowIfCancellationRequested()) если есть спобос получше?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    Во-первых, ваш заголовок вводит в заплуждение: в нем - про завершение процесса, а справшиваете вы про завешение задачи.
    Во-вторых, задача может завершаться переходом в разные конечные состояния (они фиксируются в поле Task.Status). По оператору Return задача переходит в состояние RanToCompletion, по ThrowIfCancelationRequested - Canceled. Это - два логически разных состояния завершения (есть еще и третье - завершение по необработанному исключению, Faulted). Если коду, создаывшему задачу, совсем без разницы, как именно завершилась задача и вообще, завершилась ли она, то можете делать как угодно.
    Но, очень часто код, связанной с задачей,к примеру, операция await для задачи, ведет себя по-разному, в зависимости от состояния завершения задачи, получение результата задачи - тоже. А для задачи продолжения можно задать условия, при каком состоянии завершения предыдущей задачи эта задача продолжения будет запущена. То есть, состояние завершения задачи обычно имеет значение.
    Ответ написан
    Комментировать
  • Почему прекращается работа BackgroundService?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    Работа фонового сервиса у вас прекращается потому что у его метод ExecuteAsync дожидается инициализации статической переменной WebView (она содержит ChromiumWebBrowser, открытый на странице https://web.watsapp.com) а потом ничего не ждет, а просто завершается. А что там у вас происходит с браузером, код вашего фонового сервиса не контролирует.
    PS Я не вижу ваш остальной код, но могу предположить, что вам для работы программы этот фоновый сервис не нужен, т.к. вся работа с экземпляром CefSharp идет через упомянутую статическую переменную.
    Ответ написан
    3 комментария
  • Как разбить URL на сегменты и найти его соответсвующее имя?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    В .NET есть стандартный класс System.Uri
    Посмотрите, может вам хватит его возможностей?
    Ответ написан
    Комментировать
  • Как по другому сделать?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    Вынесите описания переменных наверх, над swicth.
    int PlayerDamage ;
    int PlayerHealth;
    int PlayerResist ;
    
     switch(characterChoose)
     {
         case 0:
             PlayerDamage = 50;
             PlayerHealth = 150;
             PlayerResist = 25;
             break;
         case 1:
             PlayerDamage = 75;
             PlayerHealth = 125;
             PlayerResist = 15;
             break;
    
     }

    PS Согласен с предыдущим комментатором - инциализация через оператор switch выглядит тяжеловесно. В нынешнем C# можно записать то же самое сильно короче, через деконструкцию, например.
    PPS Держите пример с вашеми данными, как это должно выгдядеть стильно-модно-молодежно:
    int characterChoose = Convert.ToInt32(Console.ReadLine());
    (int PlayerDamage, int PlayerHealth , int PlayerResist)=characterChoose switch
    {
        0 => (50, 150, 25),
        1 => (75, 125, 15),
       //... дописать все остальные варианты
    } ;
    Ответ написан
    Комментировать
  • Как применить настройки прокси-сервера через реестр в С#?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    Браузеру надо сообщить, что настройки изменились парой вызовов процедуры InternetSetOption из WinInet.dll. Вызывать надо через P/Invoke На stackoverflow нашел пример, как это делать в Powershell.
    function Refresh-System
    {
      $signature = @'
    [DllImport("wininet.dll", SetLastError = true, CharSet=CharSet.Auto)]
    public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);
    '@
    
    $INTERNET_OPTION_SETTINGS_CHANGED   = 39
    $INTERNET_OPTION_REFRESH            = 37
    $type = Add-Type -MemberDefinition $signature -Name wininet -Namespace pinvoke -PassThru
    $a = $type::InternetSetOption(0, $INTERNET_OPTION_SETTINGS_CHANGED, 0, 0)
    $b = $type::InternetSetOption(0, $INTERNET_OPTION_REFRESH, 0, 0)
    return $a -and $b
    }

    Адаптируйте этот код к C# (пояснение: Add-Type в PS служит для загрузки сборки или неуправляемой DLL ). Или поищите по имени этой процедуры код на C#.
    Ответ написан
    5 комментариев
  • Как десериализовать простой Json в массив?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    Используйте LINQ:
    Если поле code в типе, получаемом после десериализации имеет тип int (по уму должно быть так, но я с NewtonSoft JSON не работал, поэтому не уверен в таких подробностях), просто допишите к выражению для десериализации
    .Select(x=>x.code).ToArray();
    Если тип, паче чаяния, другой - преобразуйте результат, возвращаемый лямбда-функцией в Select к int (для строки это будет Int32.Parse(x.code)
    Ответ написан
    Комментировать
  • Как правильно и удобно читать данные из БД?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    Думаю, что надо раскрыть подробнее тему предыдущих ответов и комментариев.
    Проблемы со сложностью у вас, потому что вы не используете современые средства .NET и C#.
    В .NET исторически сложилось несколько слоев API для обеспечения параллельной работы, и использование функций обратного выдова - самый старый и самый громздкий из них. А самый удобный и современный - это Task Parallel Library (TPL): он, плюс конструкции языка C# async/await, позволяет писать такой асинхронно выполняющийся код так, будто он выполняется синхронно.
    Скорее всего (я просто не уточнял, потому пишу так) для SQLite есть асинхронный API и для использования с TPL, и API для синхронного использования, что ещё удобнее - и он должен быть не менее быстрым чем синхронная работа с файлами, потому что это встроенная БД.
    Но если вы по каким-то причинам будете работать с асинхронным API на функциях обратного вызова, то тут тоже есть способ упростить код: транслировать вызовы такого API для использования его со средствами TPL. Для этого используйте объект типа TaskCompletionSource (в вашем случае - обобщенный, специалиированный вашим типом результата: TaskCompletionSource<int>
    У этого объекта есть свойство Task, возвращающее задачу, состоянием котрой можно управлять с помощью методов этого объекта - SetResult и других, вызывая эти методы в функциях обратного вызова (AKA callback). Как это делать - см. пример по ссылке.
    А с Task, каким бы способом вы его не получили, вам будет работать значительно удобнее: если пометить метод, в котором вам надо работать с БД как async (в современном C# так можно пометить даже Program.Main), то в этом методе можно будет использовать для получения значения операцию await
    TaskCompletionSource<int> tcs1=new TaskCompletionSource();
    //... операции по по настройке tcs1 и запуску первого чтения из БД
    int numberFromBase1 = await tcs1.Task.ConfigureAwait(false);
    TaskCompletionSource<int> tcs2=new TaskCompletionSource();
    //... операции по по настройке tcs2 и запуску второго чтения из БД
    int numberFromBase2 = await tcs2.Task.ConfigureAwait(false);
    int summ =  numberFromBase1 + numberFromBase2;
    return summ;

    Вызов ConfigureAwait(false) здесь нужен для избежания блокировок в некоторых контекстах синхронизации (приложения Windows Forms, WPF и др.). Если же у вас программа выполняется вне специфического контекста синхронизации - консольное приложение, приложение ASP.NET Core и др., - то этот вызов не обязателен.
    Компилятор, увидев операцию await, преобразует метод нужным образом, так, чтобы он выполнялся асинхронно, передавая управление другим задачам во время ожидания (т.е. до выполнения функции обратного вызова) и возобнавлял выполнение по его завершении -и вам думать об этом и писать нужный для этого код будет не нужно.
    Такой метод вернет Task (возможно - ещё до завершения всех операций) и с его результатом можно что-то сделать: либо получить его опять чере await асинхронно, либо дождаться завершения асинхронных операций с получением результата через вызов метода Task<int&gt.GetAwaiter().GetResult() (есть другие варианты, но этот IMHO лучше всего в плане обработки исключений).
    Ответ написан
    Комментировать
  • Нужно ли знать многопоточность и асинхронность в c#, чтобы начать учить asp.net?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    Мое мнение: есть некоторая неопределенность для ответа. С одной стороны, при решении типовых задач с помощью базирующихся на ASP.NET Core фреймворках высокого уровня - MVC, Razor, Minimal API, Blazor (за последний не совсем уверен, правда), с асинхронностью и многопоточностью вы сталкиваться будете не сильно и не часто, потому что в них приложены усилия, чтобы изолировать разработчика от связанных с этим трудностей - короче, потребуется разве что, умение использовать async/await. Но в целом ASP.NET Core - это фреймворк асинхронный и многопоточный, поэтому для более плотной работы с ним понимание асинхронность и многопоточность и связанные с ней знания (например, про примитивы синхронизации, состояние гонок и т.п.) может быть полезно, иногда - например, если вы захотите использовать объекты, к которым возможен доступ из нескольких веб-запросов параллельно - просто необходимо.
    Короче, мое мнение: начинать изучать перечисленные фреймворки высокого уровня можно и без особых знаний про асинхронность, достаточно научиться использовать await в async-методах (это просто). Но в дальнейшем тему асинхронности и многопоточности надо вкурить, чтобы можно было работать смелее и свободнее, выходя за рамки фрейворка, и не допускать при этом труднообнаружимых ошибок.
    Ответ написан
    Комментировать
  • C#, обработка исключений, почему нельзя обратится к свойству, через имя класса?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    если я не хочу создавать переменную

    А вы её и так, и так не создаете: экземпляр исключения создается при возбуждении исключения (помните синтаксис - throw new Exception() )? А вот чтобы обратиться к полям/свойствам/методам этого экземпляра, надо дать ему имя в конструкции catch и обращаться к нему по этому имени. А при указании в качестве имени экземпляра имени класса, вы, как выше вам написал Василий Банников , как и в любом другом месте, обращаетесь к статическому полю (или свойству) этого класса. Такой вот синтаксис у языка C#: обработчик исключения у него - это обычный блок, никаких специальных соглашений там нет( пока что, по крайне мере ;-) ).
    Ответ написан
    2 комментария
  • Почему надо явно добавлять пакет Microsoft.NET.Test.Sdk в гл проект, если в одном из пакетов он уже есть?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    Так нужно, потому что ссылки не транзитивны. Средства разработки не могут взять метаданные (описания сборок, классов и т.д.), которые нужны для работы и компилятора, и других средств разработки (IDE, в частности), из ссылок того проекта (по факту - тоже сборки), на который ссылается текущий. Так что для использования какой либо сборки (в данном случае - из состава пакета), ссылку на нее нужно добавлять в проект явно.
    Ответ написан
    2 комментария
  • Почему я не могу выбрать проект для дебага?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    Если надо один раз: правой кнопкой мыши на нужный проект -> Debug -> Start New Instance
    Если надо изменить на постоянку: правой кнопкой мыши на нужный проект -> Configure Startup Project...
    или Меню->Project->Startup Project...
    Предполагается, что все эти проекты входят в одно Решение (Solution)
    Ответ написан
    Комментировать
  • Почему не работает замена буфера?

    @mvv-rus
    Настоящий админ AD и ненастоящий программист
    Так, как вы сделали, приложения для Windows GUI не пишутся. У вас цикл с ожиданием сделан совершенно неправильно.
    Обработка всего графического интерфейса в программе (в том числе и буфера обмена) в Windows выполняется одним потоком, через цикл сообщений. А вы этот поток захватили и не отдаете. Возможно, именно поэтому не работает и установка содержимого буфера обмена: ЕМНИП она тоже реализована через сообщения (но точно не помню), а шанс обработать очередь сообщний у вашей программы нет.
    Короче, переписывайте цикл чтобы никаких Thread.Sleep в нем не было. Например - добавляйте в форму таймер (System.Windows.Forms.Timer) и переносите вашу обработку буфера обмена в обработчик его события Tick.
    А там уже смотрите - работает она, или нет.
    Ответ написан
    Комментировать