Ответы пользователя по тегу C#
  • Подмена реализации интерфейса без перекомпиляции проекта. Как реализовать?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    //m = new Message();
    m = MessageFactory.GetMessage();

    А вот в MessageFactory уже искать тот метод, который создаст нужный объект (например, как указал freeExec).

    Как вариант - использовать IoC-контейнер:
    1) в главной сборке создать контейнер.
    2) найти нужную сборку и передать в неё этот контейнер
    3) в той сборке забиндить нужный класс на этот интерфейс в переданном контейнере.

    Тот же приём можно использовать, когда в решении есть два проекта, второй проект использует первый проект (первый добавлен в зависимостях), а вот первому нельзя добавить второй проект в зависимостях. Решение - контейнер в первом проекте, а классы биндятся во втором. Тогда пункт 2 не нужен.
    Ответ написан
    Комментировать
  • Скрыть область видимости переменной?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Переменную можно поместить в блок, тогда переменная будет ограничена только этим блоком:
    int Test()
    {
        int result = 0;
    
        {
            int i = 10;
            for (int j = 0; j < 10; j++)
            {
                result += i;
            }
        }
        {
            string i = "xyz";
            Console.WriteLine(i);
        }
        return result;
    }
    Ответ написан
    1 комментарий
  • Как избежать проблем с Execution Order?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Я в Awake использую инициализацию самого компонента, не используя связи с другими компонентами. А в Start все компоненты уже инициализированы, их можно использовать.

    Компонент A в Start получает ссылку на компонент B. Не факт, что B уже вызвал Start и не имеет нужные ссылки. Тут два варианта
    - B тоже должен иметь ссылку на A. Тогда A может передать себя в B (до вызова B.Start).
    - B должен иметь ссылку на компонент C. Тут могут быть проблемы.

    Чтобы такие связи были независимы от порядка, то каждый компонент в Awake должен поместить себя (зарегистрироваться) в какой-то контейнер, через который в Start в любом компоненте можно получить нужную ссылку.

    Контейнером может быть
    - статическое поле класса (если компонент планируется только один, то получается типа полу-синглтон - поле устанавливается в Awake, а потом используется отовсюду во время Start и после)
    - специальный список в родителе (если компонент не одиночка)
    - IoC-контейнер
    Ответ написан
    4 комментария
  • Можно ли объявлять делегат в одном классе (методы там же), а создавать переменную, присваивать адрес метода, вызывать в другом классе?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    А кто вам мешает так делать?.. Делегат можно объявить вообще не в классе, а просто в неймспейсе. Ведь делегат - это просто сигнатура метода (количество и типы аргументов метода).
    Ответ написан
    Комментировать
  • Как реализовать Таблицу Менделеева?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Предполагаю, что делается WPF-проект.

    1. Сделать класс-вьюмодель элемента с нужными свойствами для описания элемента.

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

    3. Создание таблицы элементов. Также нужна возможность сделать пустые ячейки (например, между водородом и гелием). Список ячеек показывать через ItemsControl с нужным вариантом панели: WrapPanel или Grid. Для показа разных типов ячеек (элемент, пустая ячейка, ячейка с текстом) можно использовать различные шаблоны (указав DataTemplate c типом или через ItemTemplateSelector).

    а) (самый простой вариант) панель WrapPanel с нужной шириной таблицы и с нужной шириной/высотой элемента. Неиспользуемые ячейки просто показывать пустоту (или что-нибудь показать внутри этой ячейки). Каждая пустая ячейка должна быть в списке ячеек отдельным элементом. WrapPanel сама покажет все переданные ячейки в виде таблицы.

    б) (возможность написать что-то в строке между H и He) панель WrapPanel с нужной шириной. Во вьюмодели сделать свойство int Span для тех ячеек, которые будут заниматься несколько ячеек. По умолчанию значение 1 (одна ячейка). В контрол привязывать ширину контрола ячейки с свойством Span (с помощью конвертера, я бы назвал MultiplyConverter)

    в) (более сложно, но больше возможностей - объединение ячеек по горизонтали и вертикали) панель Grid с 8 колонками и сколько-то там строками (или какой вариант таблицы вы хотите использовать). Во вьюмодели сделать свойства Row и Col, а также RowSpan и ColSpan, привязывать их в одноимённые свойства в контроле (attached properties Grid.Row и т.п.).
    Ответ написан
    Комментировать
  • Как анимировать image в wpf при нажатии на другую кнопку?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    По кнопке изменить свойство во вьюмодели (возможно, булевое свойство). Триггер по изменению этого свойства вызовет анимацию.
    Ответ написан
    1 комментарий
  • Как включить отображение XAML Designer Window в Visual Studio 2017?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Судя по картинке, у вас студия разделила xaml и xaml.cs, а не поняла их как общую сущность. И теперь xaml показывает как простой текстовый файл. Возможно, студия не поняла, какой тип шаблона этого проекта (может, проект не созданный вновь, а подключенный существующий?).

    Создайте в этом же решении новый проект с типом WpfApplication и попробуйте дизайнер в нём. Сравните файлы csproj между вашим дефектным проектом и вновь созданным проектом.
    Ответ написан
    Комментировать
  • Для чего нужны спецификаторы доступа в C#/Java и др. подобных языках?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    class KvadrUr
    {
        public double a, b, c, D, x1, x2;
        public void CalcD()
        {
            D = b*b - 4*a*c;
        }
        public void Calc()
        {
            double d  = Math.Sqrt(D);
            x1 = (-b + d)/(2*a);
            x2 = (-b - d)/(2*a);
        }
    }
    KvadrUr ur = new KvadrUr();
    ur.a = 1;
    ur.b = 2;
    ur.c = -3;
    ur.CalcD();
    ur.Calc();
    Console.WriteLine(ur.x1 + " " + ur.x2); // правильный ответ
    ur.c = -4;
    Console.WriteLine(ur.x1 + " " + ur.x2); // неправильный ответ - теперь дискриминант неверный!

    Если сделать переменную D приватной (и вызывать CalcD внутри Calc), то это эта ошибка возникнуть не может.
    То есть, ограничение доступа к членам класса помогает уменьшать вероятность ошибки.
    Ответ написан
    Комментировать
  • Что это за конструкция public T GetService() where T: class { throw new NotImplementedException(); } в C#?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Это объявление обобщённого метода, в котором тело не определено.
    В этом коде три разных концепции:
    1) это объявление метода GetService без аргументов и с возвращаемым типом T
    2) В качестве возвращаемого типа стоит T - это обобщённый (generic) тип, реальный тип будет указан при вызове метода. Слово where указывает ограничение - реальным типом должен быть класс.
    Например, можно указать MyService x = GetSevice<MyService>(); или Person x = GetSevice<Person>(); или IWeapon x = GetSevice<IWeapon>();.
    3) в качестве тела метода стоит throw new NotImplementedException(); - возникнет исключение, указывающее, что тело не определено. Так делается, если нужно показать, что этот код вызывать не нужно, либо если тело будет написано позже, а сейчас при вызове будет исключение.
    Ответ написан
    2 комментария
  • Как полностью очистить массив?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Возможно, лучше взять список List<int> вместо массива:
    public List<int> checkAddDel;
    
    checkAddDel = new List<int>(Word.Length); // предварительно указывать размер не обязательно, 
                                              // но если известно заранее, то лучше указать
    
    Console.WriteLine(checkAddDel.Count); // 0
    for (var i = 0; i < Word.Length; i++)
    {
        checkAddDel.Add((i + 1) * 10);
    }
    Console.WriteLine(checkAddDel.Count); // размер теперь стал равным Word.Length
    
    // используем список
    DoWork(checkAddDel);
    
    checkAddDel.Clear(); // теперь стал пустым
    Console.WriteLine(checkAddDel.Count); // 0
    Ответ написан
    Комментировать
  • Как сделать выпуск софта?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Ответ написан
    Комментировать
  • Как создать систему заданий в игре?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Хороший ответ Yegor, добавлю ещё другую таблицу: условия появления заданий - какая задача появляется после какой. Туда же можно добавить другие условия: время, уровень, наличие предметов или наоборот отсутствие (исчез важный предмет - добавить необязательное задание для получения этого предмета заново).
    Ответ написан
    Комментировать
  • Как сделать так, чтобы каждый if выполнался одновременно?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Проверяйте не отдельные клавиши, а сочетания:
    var isLeftPressed = Input.GetButton("LeftArrow");
    var isUpPressed = Input.GetButton("UpArrow");
    var isRightPressed = Input.GetButton("RightArrow");
    var isDownPressed = Input.GetButton("DownArrow");
    if (isUpPressed && isDownPressed && Time.time > timeToFire)
    {
        timeToFire = Time.time + 1 / fireRate;
        Instantiate(fireSphere, firePoint.position, firePoint.rotation);
    }
    Ответ написан
    Комментировать
  • Есть ли большой туториал для изучения С# desktop + DB?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Лучшей книгой для вас будет Эндрю Троелсен "Язык программирования C# 6.0 и платформа .NET 4.6".
    Прекрасная книга для профессионалов, рассказывает обо всём в языке и почти обо всех возможностях и использованиях. В первую очередь, предназначена для программистов, которые уже умеют программировать, но не знают язык C#. В ей всё структурировано на разделы, каждый из них можно читать независимо и использовать как справочник.
    У этой книги есть только один недостаток - написана для профессионалов, и автор пишет, как делать, но не пишет, почему так делать - вы и так уже это понимаете, иначе книга стала бы совсем уж гигантской.

    Рекомендую взять время и попробовать написать несколько консольных программ на c#, начиная с моего любимого решателя квадратных уравнений :) и работы со списками (простой телефонный справочник). И только после этого начинайте работать с WPF.

    А вот очень приличный учебник по wpf:
    https://professorweb.ru/my/WPF/base_WPF/level1/inf...
    Довольно суховато написано, но с неплохими примерами.

    И опять же, рекомендую не начинать делать вашу программу, а сделать с помощью WPF те же программы, которые написали с консолью. И освойтё MVVM.
    Ответ написан
    1 комментарий
  • Почему HttpClient.GetAsync некорректно использует ссылку с символом "#"?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    После символа # указывается локальный фрагмент (или якорь) страницы - элемент внутри страницы, который использует браузер для навигации по странице. Также используется для локальных (клиентских) настроек страницы.
    В вашем случае, после # указан тип сортировки p1_name_asc - сортировать таблицу по имени по увеличению. Например, чтобы сортировать по уменьшению, можно поставить тип p1_name_desc.
    Проблема в том, что сортировка происходит в браузере, а не на сервере (сервер вообще не увидит эту часть адреса).
    Если нужно получить список именно так, как указано в ссылке, то вы тоже должны сортировать результат после получения списка.
    Ответ написан
    Комментировать
  • Какой паттерн лучше использовать при необходимости реализации методов из разных классов?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Композиция, а не наследование.
    D реализует IM1 и IM2, но не наследуется от классов A, B, C.
    class D : IM1, IM2
    {
        B _b;
        C _c;
        public D(B b, C c)
        {
            _b = b;
            _c = c;
        }
    
        public void M1()
        {
            _b.M1();
        }
    
        public void M2()
        {
            _c.M2();
        }
    }
    Ответ написан
    Комментировать
  • Как проще округлить три числа подряд, не используя итерацию, на C#?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Без цикла только так, как вы сказали (с вариантами в виде создания временных переменных с результатами). Иначе нужен цикл. Но цикл может быть внутри какой-нибудь функции, например, в string.Join. И то, всё равно придётся вручную поместить данные в массив.
    double a = 10.123, b = 20.234, c = 30.345;
    Console.WriteLine(Math.Round(a, 2) + " " + Math.Round(b, 2) + " " + Math.Round(c, 2));
    Console.WriteLine(string.Join(" ", new []{a, b, c}.Select(x => x.ToString("F2"))));


    Ещё можно попробовать изгальнуться - поместить данные в поля и получить список полей через рефлексию.
    Ответ написан
    2 комментария
  • Как использовать объект из другого метода в консольном приложении C#?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Обратиться к объекту можно обратиться только по ссылке на него. Если есть ссылка - можно использовать.
    Ссылка на объект port1 сохранена в локальной переменной метода Data. После окончания вызова этого метода, все локальные переменные исчезают. Чтобы обратиться на этот объект из другого метода, есть несколько способов:
    1) сохранить ссылку в поле класса, а не в локальную переменную. Доступ к полям есть во всех методах класса (кроме статических).
    2) если второй метод вызывается из первого, то во второй метод можно передать ссылку аргументом. У вас второй метод не вызывается из метода Data, в этом случае, так не получится использовать.
    3) сам объект может передать ссылку на себя другим объектам, тогда те смогут его использовать (это как раз у вас и происходит, как и сказал Петр)

    Обратите внимание, что если бы вы не сделали добавление обработчика события, то после завершения вызова метода Data, не оставалось бы ни одной ссылки на этот объект, и сборщик мусора (GarbageCollector, GC) отметил бы его мусором и удалил бы его (раньше или позже). А раз вы сделали обработчик события, то этот объект не является мусором (он используется другим объектом). Мусором он станет, когда вы удалите обработчик события.

    Каким способом передавать ссылку лучше всего? В зависимости от контекста (т.е. от способа использования этого объекта):
    1) если вы создали временный объект, который вы использовали и больше не нужен, то передавайте ссылку на него аргументами при вызове методов, его используемых. Когда объект больше не нужен, GC быстро и безболезненно удалит его.
    2) если вы создали постоянный объект, который должен работать какое-то время после окончания метода, в котором объект создан, то нужно положить ссылку на него в поле класса (или в список, или ещё куда-нибудь). Пока есть ссылка, остаётся объект. Когда он уже не нужен, то нужно удалить ссылку на него (присвоить в поле null или новую ссылку, удалить из списка и пр.). Не забывайте обнулять ссылки на не нужные объекты!
    3) Можно использовать косвенные ссылки (например, обработчики события), но это обычно неудобно - не ясно, когда исчезнут ссылки на объект, а в некоторых случаях, удалить обработчик уже не получится (опять же, это сложно сделать без ссылки). Подобные вещи - места для трудноуловимых багов. Поэтому, лучше использовать способы 1 или 2.
    Ответ написан
    Комментировать
  • Как заменить switch case паттерном стратегия?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Switch
    public enum DamageType { Melee, Range, Magic }
    public class Monster
    {
        public double Health { get; private set; }
        public double MeleeDamage { get; private set; }
        public double RangeDamage { get; private set; }
        public double MagicDamage { get; private set; }
        public DamageType FavoriteDamageType { get; private set; }
    
        public Monster(double health, double meleeDamage, double rangeDamage, double magicDamage, DamageType favoriteDamageType)
        {
            Health = health;
            MeleeDamage = meleeDamage;
            RangeDamage = rangeDamage;
            MagicDamage = magicDamage;
            FavoriteDamageType = favoriteDamageType;
        }
    
        public void AttackTo(Monster monster, DamageType damageType)
        {
            switch (damageType) // используется switch
            {
                case MonsterType.Melee: monster.Health -= MeleeDamage; break;
                case MonsterType.Range: monster.Health -= RangeDamage; break;
                case MonsterType.Magic: monster.Health -= MagicDamage; break;
            }
        }
    
        public void AttackTo(Monster monster)
        {
            AttackTo(monster, FavoriteDamageType);
        }
    }


    То же самое, но со стратегией
    public class Monster
    {
        public double Health { get; set; }
        public double MeleeDamage { get; private set; }
        public double RangeDamage { get; private set; }
        public double MagicDamage { get; private set; }
        public IDamageStrategy FavoriteDamageStrategy { get; private set; }
    
        public Monster(double health, double meleeDamage, double rangeDamage, double magicDamage, IDamageStrategy favoriteDamageStrategy)
        {
            Health = health;
            MeleeDamage = meleeDamage;
            RangeDamage = rangeDamage;
            MagicDamage = magicDamage;
            FavoriteDamageStrategy = favoriteDamageStrategy;
        }
    
        public void AttackTo(Monster monster, IDamageStrategy damageStrategy)
        {
            damageStrategy.Attack(this, monster); // не используется switch
        }
    
        public void AttackTo(Monster monster)
        {
            AttackTo(monster, FavoriteDamageStrategy);
        }
    }
    
    
    public interface IDamageStrategy
    {
        void Attack(Monster attacker, Monster defender);
    }
    public class MeleeDamageStrategy : IDamageStrategy 
    {
        public void Attack(Monster attacker, Monster defender)
        {
            defender.Health -= attacker.MeleeDamage;
        }
    }
    public class RangeDamageStrategy : IDamageStrategy 
    {
        public void Attack(Monster attacker, Monster defender)
        {
            defender.Health -= attacker.RangeDamage;
        }
    }
    public class MagicDamageStrategy : IDamageStrategy 
    {
        public void Attack(Monster attacker, Monster defender)
        {
            defender.Health -= attacker.MagicDamage;
        }
    }

    Отличие класса Monster только в коде первого метода AttackTo. Ну и свойства FavoriteDamageType или FavoriteDamageStrategy.

    Стратегия может быть полезна, если код атаки, в зависимости от типа, сильно отличается, используя внешние данные (не из класса монстра), например, день или ночь, ясно/дождь и пр. Использование стратегии переносит часть кода из класса монстра (и так сложного класса) в несколько простых классов.
    Ответ написан
    1 комментарий
  • Как сделать фильтрацию .where() в Immediate Window?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Сделайте метод, в котором фильтруйте циклом, а не Linq-запросом.
    Ответ написан
    Комментировать