Ответы пользователя по тегу C#
  • Entity Framework - не нужен?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    EF вам дает возможность автоматически транслировать экспрешны в диалекты SQL и маппить это на удобные дотнетные сущности. С голым ADO.NET вы будете делать то же самое, но руками.

    куда логичнее было бы, чтобы в объекте Order было поле типа Client, в котором лежит объект компании-получателя, а не условный int с идентификатором.

    Предлагаемая вами схема денормализована, вообще говоря, это не очень хорошо. Но посмотрите на Owned Types для EF Core и на Complex Types для EF6, мне кажется, что это то, что вы хотели бы - "встраивать" один объект в другой, сохраняя всё в единой таблице.

    Да, EF не то, чтобы позволяет сильно отходить от классической реляционной модели, но с ним можно точечно звать raw sql-queries, что даст больше гибкости там, где это необходимо.
    Ответ написан
  • Как сделать обновление миграции EFCore?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    При каждом изменении моделей и/или их связей, нужно сначала сгенерировать очередную миграцию (Add-Migration), а затем - накатить изменения на схему (Update-Database).

    В CLI будет так:
    dotnet ef migrations add NewMigrationName;
    dotnet ef database update;


    Подробнее читать тут.
    Ответ написан
  • Что учить дальше после основ C#?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Базы данных и СУБД, архитектурные паттерны, платформу .NET вглубь. Дальше - в зависимости от интересующей специфики.
    Ответ написан
  • Добавление записей в доп. таблицу, имеющей связь с основной таблицей?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    var newPerson = new People {
       //Id = model.Id,
       Name = model.Name,
       Treatment = new Treatment {
            //...
       },
    };
    
    dbCcontext.People.Add(newPerson);
    dbCcontext.SaveChanges();
    Ответ написан
  • Что с точностью float?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Получается float не надёжен?

    Смотря кому, когда и как. Всё зависит от того, какая точность важна в конкретной задаче. Деньги на нем не считают, но для большого круга задач этой точности вполне хватает, а эффективность кода с double гораздо выше, чем decimal.

    float нужен лишь затем, что этот тип занимает вдвое меньше памяти, чем double. Где-то это может сыграть решающую роль.

    ЗЫ В конкретной ситуации вас спасёт Math.Round
    Ответ написан
  • Как правильно написать этот код/как оптимизировать это "код"?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Первое, что нужно сделать - определить доменные сущности, с которыми будет работать программа. В вашем случае это:
    • тест, который состоит из вопросов;
    • вопрос, который состоит из текста и ответов (упорядоченные по индексам);
    • ответ, котрый состоит из текста и признака правильности.
    Код
    public class Test
    {
        public IList<Question> Questions { get; set; }
    }
    
    public class Question
    {
        public string Text { get; set; }
        public IList<Answer> Answers { get; set; }
    }
    
    public class Answer
    {
        public string Text { get; set; }
        public bool IsRight { get; set; }
    }



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

    1. логика "главного меню";
    2. логика теста:
      1. создание контента теста;
      2. прохождение теста:
        1. распечатка вопроса;
        2. получение ввода пользователя;
        3. проверка ответа;
        4. подсчет и вывод статистики.



    Затем необходимо сформировать структуру теста. Для этого можно создать функцию-фабрику, которая возвращает новый объект теста (данные хардкодятся как здесь, читаются из базы, ходят за ними в интернет... whatever, нас интересует само тестирование):
    Код
    public static Test CreateTest()
    {
        return new Test
        {
            Questions = new List<Question>
            {
                new Question
                {
                    Text = "Какая команда выводит текст в консоль?",
                    Answers = new List<Answer>
                    {
                        new Answer { Text = "if/else" },
                        new Answer { Text = "System.out.println();" },
                        new Answer { Text = "Console.WriteLine();", IsRight = true },
                        new Answer { Text = "int x = 10;" }
                    }
                },
                new Question
                {
                    Text = "Какой тип из списка целочисленный?",
                    Answers = new List<Answer>
                    {
                        new Answer { Text = "char" },
                        new Answer { Text = "int", IsRight = true },
                        new Answer { Text = "float" },
                        new Answer { Text = "double" }
                    }
                }
                //,...
            }
        };
    }


    Пусть программа, как у вас, приветствует пользователя, а затем, пока он не введет какой-то из двух корректных выводов (регистронезависимо (...IngoreCase)), будет показывать приглашение с подсказкой. Если Go - вызываем создание теста и заходим в игру. Если игра завершилась или пользователь изначально ввел Exit - печатаем знаменитое Press any key... и выходим из программы.
    Код
    public static void Main()
    {
        Console.WriteLine("Всем привет! И это моя первая мини-программа для проверки ваших знаний языка программирования C#");
        string input;
        
        do
        {
            Console.WriteLine("Если готовы пройти тест напишите Go, а если хотите выйти напишите Exit.");
            input = Console.ReadLine();
    
            if (input.Equals("Go", StringComparison.InvariantCultureIgnoreCase))
            {
                var test = CreateTest();
                PlayGame(test); // <----- Логика тестирования находится здесь
            }
        } while (   !input.Equals("Go", StringComparison.InvariantCultureIgnoreCase)
                 && !input.Equals("Exit", StringComparison.InvariantCultureIgnoreCase));
    
        Console.WriteLine("Для выхода нажмите любую клавишу...");
        Console.ReadKey();
    }


    Для игры нам потребуется массив с номерами "проваленных" вопросов (которые пригодятся для статистики в конце - CalculateResult). Мы обходим все вопросы из теста, сначала выводя их текст с вариантами на экран (PrintQuestion), затем спрашивая юзера его выбор (GetUserChoice). Затем ответ проверяется (IsCorrectAnswer), если он неверен - добавляем номер ответа (i - это индекс массива с нуля, поэтому +1) в массив ошибок. После всех вопросов - подсчитываем и выводим статистику.
    Код
    private static void PlayGame(Test test)
    {
        var mistakes = new List<int>();
        for (int i = 0; i < test.Questions.Count; ++i)
        {
            var question = test.Questions[i];
            PrintQuestion(question, i);
    
            int choice = GetUserChoice(question.Answers.Count);
    
            if (!IsCorrectAnswer(choice, question.Answers))
            {
                mistakes.Add(i + 1);
            }
        }
    
        CalculateResults(test.Questions.Count, mistakes);
    }


    Вопрос распечатывается элементарно: сначала его текст, затем варианты ответов, перед которыми ставиться табуляция (\t), чтобы сформировался отступ списка:

    Код
    private static void PrintQuestion(Question question, int questionIndex)
    {
        Console.WriteLine($"{questionIndex + 1}. {question.Text}");
    
        for (int i = 0; i < question.Answers.Count; ++i)
        {
            Console.WriteLine($"\t{i + 1}. {question.Answers[i].Text}");
        }
    }


    Получение варинта юзера делается циклом аналогичным вводу Go/Exit в начале. Его завершением управляет переменная isCorrectInput, которая ставится равной true только в самом конце, когда значение успешно спарсится и пройдет проверку на валидность номера ответа (от 1 до максимального номера ответа):
    Код
    private static int GetUserChoice(int answersCount)
    {
        bool isCorrectInput = false;
        int choice = -1;
        do
        {
            try
            {
                Console.WriteLine("Введите номер ответа:");
                string input = Console.ReadLine();
                choice = Convert.ToInt32(input);
                if (choice >= 1 && choice <= answersCount) isCorrectInput = true;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Неправильный формат ввода");
            }
        } while (!isCorrectInput);
    
        return choice;
    }


    Для проверки правильности сначала выделяем правильные ответы вопроса (rightAnswers), а потом сравниваем их порядковые индексы с выбранным пользователем индексом. Если хоть один ответ совпал (да, их может быть несколько) - вернется true:
    Код
    private static bool IsCorrectAnswer(int choice, IList<Answer> answers)
    {
        var rightAnswers = answers.Where(x => x.IsRight);
        int chosenAnswerIndex = choice - 1;
        return rightAnswers.Any(x => answers.IndexOf(x) == chosenAnswerIndex);
    }


    Ну и вишенка - распечатка результатов. Если ошибок нет - все гуд, 100% решений. Если ошибки есть, то мы решаем простую пропорцию, вычисляя сколько процентов ошибочных ответов было дано, а затем вычитаем их из 100%, получая процент успеха.
    Код
    private static void CalculateResults(int questionsCount, IList<int> mistakes)
    {
        if (mistakes.Count == 0)
        {
            Console.WriteLine("Вы на все вопросы ответили правильно! Тест пройден на 100%! ");
        }
        else
        {
            string invalidQuestionsString = string.Join(", ", mistakes.Select(x => $"#{x}"));
            int progressPercentage = 100 - (int)Math.Ceiling(100 * (double)mistakes.Count / questionsCount);
            Console.WriteLine($"Среди ваших ответов есть неправильные ({mistakes.Count}: {invalidQuestionsString})). Тест пройден на {progressPercentage}% ");
        }
    }



    ЗЫ Вы можете поиграть с кодом, попробовать добавить больше вопросов, принудительное прерывание после первого неправильного ответа, обработку множественных корректных ответов (добавлять или баллы за частичное угадывание), разнообразить типы вопросов и прочее.

    Полный листинг на ideone
    Ответ написан
  • Как сработает переопределение?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Метод помечен виртуальным (virtual), поэтому компилятор подставляет код виртуального вызова метода (IL-инструкция callvirt), а не непосредственного (call). В дотнете у каждого объекта есть неявная ссылка на его соответствующий (реальный) объект-тип. Через эту ссылку находится адрес правильного метода.

    В других языках все может быть устроено иначе. А об устройстве дотнета более подробно вы можете почитать в книжке Джеффри Рихтера "CLR via C#...".
    Ответ написан
  • Кто может разжевать асинхронные контроллеры?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    await еще не означает создания дополнительный поток (тред). Особенно, когда дело касается асинхронного ввода-вывода.

    В десктопных приложениях в основном потоке есть Главный Цикл (event loop), который в свободное от обработчиков время перемалывает очередь сообщений окна (дёргает эти самые обработчики в ответ на соответствующие события, вроде нажатия кнопок). Если обработчик попался слишком жирный, то сообщения не обрабатываются - окно перестает реагировать на сообщения.

    В вебе (ASP.NET) же каждому новому запросу выделяется новый поток. Если запросы выполняются слишком медленно, а клиенты поступают и поступают, то есть риск исчерпать thread pool. Как правило, самые медленные действия - это ввод-вывод, при которых поток нашей программы ничем не занят, кроме ожидания. Но операционные системы могут делать асинхронный ввод-вывод (сигналить, когда данные были прочтены/записаны), так почему бы нам не вернуть напрасно простаивающий поток в тредпул? А когда данные считаются - мы выделим поток и вернемся к задачке.
    Ответ написан
  • Как создать POST запрос без нажатия кнопки?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Вызвать вручную событие формы
    document.querySelector('form').submit();

    или же POST-запрос с помощью ajax (XMLHttpRequest)
    Ответ написан
  • Как правильно возвращать ошибки из контроллеров ASP NET MVC 5?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Рассмотрите еще фильтры, как точку перехвата исключений.

    Обычно возвращаемая вебная API-модель выглядит примерно так:
    {
        "isSuccess": true,
        "errorCode": 0,
        "errorMessage": null,
        "skip": 0,
        "take": 1,
        "data": {...}
    }

    Данные в нее заворачиваются (поле data).

    Ответ генерируется как в контроллерах (успех или ошибки бизнес-правил), так и из перехваченных исключений фильтрами.
    Ответ написан
  • Загрузить 350000 строк на сервер, как сделать?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Можно попытаться разбивать файл на чанки и их поэтапно отправлять разными запросами.
    Ответ написан
  • Пишу таск-менеджер на ASP.NET. Как реализовать подсчёт времени выполнения задачи?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Не нужно хранить в базе ActualPerformanceTime, т.к.
    1. значение будет пересчитываться при каждом новом запросе
    2. оно должно допускать разрывы (паузы)

    Можно каждой таске сопоставить таблицу один-ко-многим с временными отрезками:
    class MyTimeSpan {
        public int Id { get; set;}
        public DateTime From { get; set; }
        public DateTime? To { get; set; }
    
        public int TaskId { get; set;}
        public Task Task { get; set;}
    }

    При старте MyTimeSpan.To остается null, при Stop или Pause - отрезок "закрывается". Если хоть один отрезок не закрыт, то таска находится в прогрессе (Task.TaskStatus не нужен. Тем более, что название свойства - тавтология).
    Ответ написан
  • Как из БД вытащить файл?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Имеющий руки да загуглит!

    public ActionResult Index()
    {
        byte[] contents = GetPdfFileData();
        return File(contents, "application/pdf", "test.pdf");
    }
    Ответ написан
  • Как заменить блок html текста?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    то есть экранируются двойные кавычки...

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

    Вы уверены, что здесь правильно используется StringBuilder? Сейчас от него нет толка, ибо на каждой итерации цикла он возвращает и записывает строку, которая станет ненужной на следующей итерации, т.е. память все равно забивается, аллокации происходят. Какая-то преждевременная оптимизация.

    Убедитесь, что он заменяемое значение действительно там содержится. HtmlAgilityPack вполне может оптимизировать HTML (тот, который из OuterHtml), скажем, вырезать пробелы и/или переводы строки.
    Если вы работаете с DOM-парсером, то нужно не изобретать велосипеды, а пользоваться его API:
    string htmlTag = "<foo>bar</foo>";
    var newNode = HtmlNode.CreateNode( htmlTag );
    img.ParentNode.ReplaceChild(newNode, img);
    Ответ написан
  • Как задать кастомное называние для foreign key поля?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    https://msdn.microsoft.com/en-us/library/jj591620(...
    modelBuilder.Entity<Course>() 
        .HasMany(t => t.Instructors) 
        .WithMany(t => t.Courses) 
        .Map(m => 
        { 
            m.ToTable("CourseInstructor"); 
            m.MapLeftKey("CourseID"); 
            m.MapRightKey("InstructorID"); 
        });
    Ответ написан
  • C#. Как удалить часть строки которая идет после последнего символа, например запятой?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    удалить часть строки которая идет после последнего символа

    aaa = aaa.Substring(0, aaa.LastIndexOf(',') + 1);
    Ответ написан
  • Порядок изучения C#?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Чем еще дополнить свою библиотеку?

    Что-то про базы данных (MSSQL Server в частности, вроде Виера.Р. "Программирование баз данных MSSQL Server для профессионалов") и о каких-то прикладных технологиях, которыми вы бы хотели заниматься (ASP.NET MVC, WPF и т.п.).
    Для общего профессионального развития неплохо бы почитать что-то про операционные системы (Таненбаум, тот же Рихтер о программированнии под Windows на C/C++) и сети.

    Стоит ли уделять программированию как больше времени, вплоть до 24/7

    Если хотите убить интерес к сфере как можно скорее, то это идеальный план.

    Ну и, да, посмотреть на реальный проект будет вполне полезно для новичка.
    Ответ написан
  • Как соединить выбранное значение DropDownList с @Url.Action?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    HTML-формы, либо с помощью js изменять параметры GET-запроса.
    Ответ написан