• Generic Типы и двойной UpCast?

    Nipheris
    @Nipheris Куратор тега C#
    Вы не совсем верно понимаете ковариантность в generic-интерфейсах и напутали в кучу много всего.

    Во-первых, тип поля figure ни на какой другой не меняется. Он не может измениться "на ходу", т.к. конкретный объект конкретного класса уже создан.

    Тип возвращаемого значения свойства Figure также не меняется.
    Еще раз повторюсь - у класса и у его экземпляра не меняются никакие типы ни полей, ни свойств.

    Вы почему-то воспринимаете приведение типа класса к интерфейсу как конвертацию значения объекта - как будто создастся другой Circle, у которого будут другие типы полей. Совершенно точно это не так.

    Когда речь идёт о ссылочных типах (а полиморфизм с использованием интерфейсов работает только с такими типами), то вам следует четко понимать, что вы работаете со ссылкой, и приведение типа для ссылки никак не может влиять на сам объект. Иными словами, вы просто меняете "окно", через которое смотрите на объект.

    Таким образом, ковариантность в случае интерфейсов - это вопрос исключительно типизации. Когда в C# добавили ко- и контрвариантность, фактически вам разрешили считать, что IContainer это частный случай IContainer, а раз так - то ВСЯКИЙ IContainer можно трактовать как IContainer. В ранних версиях языка этого нельзя было сделать - можно было только Container трактовать как IContainer.

    Если в ответе что-то непонятно, спрашивайте, т.к. по вашему вопросу создаётся ощущение, что у вас где-то большой пробел в понимании языка. Вы закапываетесь в детали, делая совершенно неверные предположения о происходящем.
    Ответ написан
    9 комментариев
  • Для чего нужен Docker?

    @spotifi
    Внутри Docker только Linux, и, экспериментально, FreeBSD. Запускается нативно под Linux и, экспериментально, под FreeBSD. Под MacOSX, Windows - через виртуальную машину.

    Докер - это двойная изоляция. Изоляция того, что лежит внутри контейнера Докера от операционной системы и изоляция операционной системы от того, что лежит внутри Докер. Изоляция подразумевает изоляцию всех файлов, портов, приоритетов.

    Это почти виртуальная машина. Почти, да не совсем.


    Есть такое понятие "ад зависимостей". Любое ПО устанавливаемое на компьютер, тянет за собой зависимости (конфигурационные файлы, статические файлы называемые обычно asset, вспомогательные утилиты/сервисы, библиотеки и пр.). Ряд из этих библиотек/утилит/сервисов несовместим друг с другом. А с учетом того, что каждая из этих библиотек/утилит/сервисов имеет и свои зависимости - ситуация еще хуже.

    Например, мы используем Yandex.Cocaine, которая нормально компилируется только на Ubuntu 14.04 (и, вроде, на Debian 7). Но не под CentOS 6, 7, Debian 8, FreeBSD 9, 10, Ubuntu 15, 16 и пр. - скомпилировать его невозможно. Запускаем в этих операционных системах в Докере.

    С другой стороны, и одновременно с этим, вам необходимо установить другое, более современное ПО. И одновременно более старое. Причем речь даже не идет об серьезно отличающихся версиях Linux. Например, одно ПО требует не менее Ubuntu 14.10, а другое не более Linux 14.04.

    Docker - это одна программа внутри индивидуального окружения с индивидуальной версией операционной системы. За счет слоеных контейнеров, если вы используете один корень для всех образом, то размер Docker контейнера всего-то на несколько килобайтов больше размера бинарного файла, запускаемого под Docker.

    Таким образом, мы имеем бинарный файл запускаемый как бы в своей операционной системе.

    Вы можете сказать - ба, да это же давно известная виртуальная машина. Но нет, это не так. Это так называемые контейнера. Никакой виртуальной машиной там и не пахнет. За исключением Windows и MacOSX, где работа без виртуальном машины пока экспериментально возможно только, а нормой в этих ОС является использование Докера внутри полноценной виртуальной машины.

    Но виртуальные машины с Докером используются только для разработки. Для запуска в production виртуальные машины с Докер не используются.

    Докер использует контейнеры операционной системы. LXC в Linux, Jails в FreeBSD. Контейнер - это область операционной системы, изолированная от основной части операционной системы. В контейнере свое дерево каталогов (включая системные /dev, /bin, /sbin и пр.), свои сетевые порты и пр. и пр.

    Но при этом не используется полная виртуализация. Что существенно экономит ресурсы. Запустить 100 полноценных виртуальных машин вряд ли получится даже на мощном сервере. А вот запустить 100 контейнеров Docker даже на слабом домашнем компьютере - возможно.

    Правда использование не полной виртуализации ограничивает использование операционных систем внутри контейнеров. Как правило, это специально подготовленные версии Linux или FreeBSD. Именно специально подготовленные. Windows - в принципе в контейнере запустить невозможно.

    Контейнеры существовали и до Docker. Докер, строго говоря, это всего лишь очень удобный набор инструментов, собранных воедино, для управления контейнерной виртуализацией. Но очень удобный.

    Зачем это используется?

    Ребята из всяческих Dropbox, Facebook и и пр. гигантах, запускающие по 1 млн. различных программ в своих сервисах, столкнулись, что невозможно везде гарантировать идентичные настройки операционной системы. А это критично.

    Вплоть до того, что идеально написанная и оттестированная программа на реальном сервере начинает себя вести непредсказуемо.

    Поэтому кто-то из этих умных ребят родил новую концепцию - каждая программа на серверах запускается в своем индивидуальном окружении, с индивидуальными настройками операционной системы.

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

    Это позволяет гарантировать гораздо большую идентичность среды разработки и среды исполнения.

    До этого люди мучались, придумывали хитрые инсталяторы...

    Потом плюнули на попытки упорядочить окружение в ОС - и сейчас концепция такова - устанавливать программы на сервера вместе со своими индивидуально настроенными под них операционными системами - то есть внутри контейнеров. 1 контейнер = 1 настройка ОС = 1 программа внутри.

    Другими словами:
    • Докер-контейнер нужно использовать для отладки.
    • Тот же Докер-контейнер нужно использовать и на сервере.


    Это позволяет не трудиться с настройками "под сервер" локально на машине разработчика. Это позволяет разрабатывать на машине разработчика совершенно разные программы одновременно, которые требует несовместимых настроек операционной системы. Это позволяет давать гораздо больше гарантий, что программа на сервере будет вести себя также как и на машине разработчика. Это позволяет разрабатывать под Windows/MacOSX с удобным "прозрачным" тестированием под Linux.

    Докер применим к созданию/настройке только серверного программного обеспечения под Linux (экспериментально под FreeBSD). Не для смартфонов. А если десктопов - то только программное обеспечение без GUI.

    Посколько Докер позволил одним махом упростить работу разработчикам и админам и повысить качество результата - сейчас бум на Докер. Придумано огромная гора инструментов для управления развертыванием приложений созданных с Докером. Если раньше чтобы запустить 10 000 программ на 1000 серверах нужно было как минимум 3 высококвалифицированнейших девопса, которые писали кучу описаний как это сделать на Puppet, Salt, Chef, Ansible, да и то не было гарантий, это все тестилось месяцами. То сейчас с Докер даже один квалифицированных девопс может рулить миллионами программ на десятках тысяч серверов. С куда как большей гарантией, что все это заведется нормально.

    UPD:

    Может сложиться ложное впечатление, что разработчик готовит контейнеры в Докер, а потом передает их админу.
    Правильная методология все же другая:

    Разработчик отдает весь свой результат в систему CI (обычно через git)
    CI на каждый новый коммит делает с помощью Docker образ для тестирования.
    Если тесты проходят успешно, то этот же самый Docker образ, отправляется на развертывание в production.
    Или, чуть иначе в компилируемых системах, где исходники не нужны в production: в Docker производится развертывание среды для компиляции, а для тестирования разворачивается второй образ с уже откомпилированным добром, который уже отправляется в production.

    То есть при правильной огранизации дела разработчик не может/не должен влиять на то, какой будет образ.
    А вот в тестовой среде (запускаемом на сервер, недоступном разработчику в больших командах) и в production как раз используется один и тот же образ.

    Основная идея - что тестировали, ровно то и запускаем на боевом сервере. Один-в-один, включая те же самые файлы (не такие же, а именно те же самые).
    Ответ написан
    18 комментариев
  • Нужно ли выполнять отписку от события, содержащемся в объекте, который будет собран GC?

    Is it necessary to explicitly remove event handler...
    Отвечает Jon Skeet.

    .. The tricky case is when the publisher is long-lived but the subscribers don't want to be - in that case you need to unsubscribe the handlers..

    Если источник события скоро будет собран, на него нет других ссылок, и на подписчика ссылается только источник, то не обязательно отписываться.

    Я представляю себе это как от дерева отпала ветка на которой есть другие веточки с листьями, внутри они сами на себя могут ссылаться сколь угодно, но т.к. нет ссылки на само дерево их породившее, то такая ветка будет собрана GC.
    Ответ написан
    Комментировать
  • Нужно ли выполнять отписку от события, содержащемся в объекте, который будет собран GC?

    @rare
    Я попытался смоделировать вашу ситуацию и получилось, что не отписка не приводит к утечке памяти. Я использовал финализатор, чтобы отследить сборку мусора. В конце теста примерно 14% объектов не уничтожено, но вызов GC.Collect() приводит к их уничтожению. Я это интерпретирую так, что GC распознает эти объекты как мусор, просто еще не добрался до них. Это связано и с использованием кастомного финализатора: для уничтожения таких объектов сборщику мусора нужно больше времени. Подробнее про события https://habrahabr.ru/post/89529/
    class Program
    {
        private static bool Unsubscribe = false;
        static void Main(string[] args)
        {
            var ship = new Ship();
            Enumerable.Range(0, 100000).ToList().ForEach(i =>
            {
                Console.Write($"\r{i + 1}\t");
                ship.MyTask = new MyTask(i);
                ship.MyTask.TaskCompleted += OnTaskCompleted;
                ship.MyTask.DoAndRaise();
            });
    
            ship.MyTask = null;
    
            Console.WriteLine();
            Console.WriteLine("Raised: " + MyTask.EventsRaised);
            Console.WriteLine("Collected: " + MyTask.Collected);
            GC.Collect();
            GC.WaitForPendingFinalizers();
            Console.WriteLine("Collected: " + MyTask.Collected);
        }
    
        static void OnTaskCompleted(object semder, int taskId)
        {
            if (Unsubscribe)
            {
                var mt = semder as MyTask;
                mt.TaskCompleted -= OnTaskCompleted;
            }
        }
    }
    
    public class MyTask
    {
        public static int Collected, EventsRaised;
        public MyTask(int id)
        {
            TaskId = id;
        }
    
        public int TaskId { get; }
    
        public event EventHandler<int> TaskCompleted;
    
        public void DoAndRaise()
        {
            TaskCompleted?.Invoke(this, TaskId);
            Interlocked.Increment(ref EventsRaised);
        }
    
        ~MyTask()
        {
            Interlocked.Increment(ref Collected);
        }
    }
    
    public class Ship
    {
        public MyTask MyTask { get; set; }
    }
    Ответ написан
    Комментировать
  • Поиск сдвига одного изображения относительно другого?

    @nirvimel
    Про OpenCV не подскажу, но я бы написал это вручную. Идея простая: Задаем функцию которая проверяет истинность (точнее обратное ей значение, типа "ложность") гипотезы что второе изображение является первым изображением, сдвинутым по осям ровно на значения X, Y. Эта функция рассчитывается (например) как сумма квадратов разностей значений соответствующих пикселов первого изображения и второго, сдвинутого на -X, -Y. Имея такую функцию дальше просто находим ее минимум методом градиентного спуска (начальные значения X=0, Y=0), полученные X, Y и будут рассчитанными значениями смещения второго изображения от первого.
    С поворотом все аналогично, только добавляется еще одна одна переменная - градус поворота. Но функция проверки гипотезы становится значительно тяжелее в вычислительном плане: на каждый пиксел пойдет минимум одна тригонометрическая функция (относительно тяжелая для CPU), плюс этим обламывается SIMD оптимизация, которая дает многократное ускорение для первого варианта без поворота.
    Ответ написан
    1 комментарий
  • Возможно ли создать free2play игру на Unity?

    donkaban
    @donkaban
    Умею рисовать тени
    Нет, конечно. F2P игры делаются исключительно на UE4!
    Ответ написан
    2 комментария
  • Как связать две иерархии классов?

    Nipheris
    @Nipheris Куратор тега C#
    Если вы обязаны жить с разделением архитектурных слоёв, о котором вы упомянули и не можете ничего поменять: первый вариант "тип" - "инициализатор" вижу наиболее удобным. Все равно придется добавлять маппинг при добавлении нового типа объекта.
    Вообще можно конечно продолжить извращение и воспользоваться рефлексией и сделать автомаппинг классов "модели" на наследников GameObject. Например, искать все классы "модели" в определенном неймспейсе и искать такие же в другом (которые, в свою очередь, будут наследниками от GameObject).

    Вообще, вы в каком-то смысле идете вразрез с архитектурой самого движка, т.к. GameObject-ы - это не только "представление", а и модель тоже. Я понимаю, что вы наверное не хотите создавать тяжелые GameObject-ы, когда они вроде как не нужны еще (т.е. не в области видимости), но возможно, если не добавлять их в сцену, они не будут нагружать движок.
    В общем, у меня есть сомнения в том, что такое разделение на модель и представление при использовании Unity - хорошая практика.
    Ответ написан
    1 комментарий
  • Git bash - или или баг?

    zagayevskiy
    @zagayevskiy
    Android developer at Yandex
    Это не глюк, это типа "интерактивный режим", в нём можно стрелками вверх-вниз по истории перемещаться. Для выхода в нормальный режим надо нажать "q".
    Ответ написан
    Комментировать
  • Что, кроме Visual Studio, умеет строить карты кода?

    abyrkov
    @abyrkov
    JavaScripter
    Есть дополнение миникарта для Атома. Но, аналогично Евгению, не знаю, насколько похоже на карту кода ВС
    Ответ написан
    Комментировать
  • Что, кроме Visual Studio, умеет строить карты кода?

    @rsi
    software engineer
    В IntelliJ IDEA есть такая штука - https://www.jetbrains.com/idea/help/viewing-diagra... Не знаю на сколько функционал схоже с картой из Visual Studio
    Ответ написан
    3 комментария
  • Как обойти ограничение на отсутствие параметров у конструктора класса generic типа?

    @MonkAlex
    C#, SQL, Delphi, C++ etc
    Сама идея такой зависимости мне не нравится, но понять ЗАЧЕМ - я не могу.
    public class Component
      {
        public Component(SceneObject ownerSceneObject)
        {
          this.ownerSceneObject = ownerSceneObject;
        }
        public readonly SceneObject ownerSceneObject;
      }
    
      public class SceneObject
      {
        private List<Component> components;
         
        public void AddComponent<T>() where T : Component
        {
          var constructor = typeof(T).GetConstructor(new [] { typeof(SceneObject) });
          var created = constructor.Invoke(new object[] { this }) as T;
          if (created != null)
            this.components.Add(created);
        }
    
        public SceneObject()
        {
          this.components = new List<Component>();
        }
      }
      }
    Ответ написан
    2 комментария
  • Как подключиться к узлу в подсети?

    Energoblock
    @Energoblock
    Geek
    Если подсеть 192.168.1.0/24 вам действительно необходима, то на роутере 192.168.1.1 сделайте проброс порта 192.168.1.2:80 на порт 80. После таких манипуляций компьютеры из сети 192.168.0.0/24 смогут обращаться по адресу 192.168.0.2 на порт 80.

    Но для домашней сети логичнее во втором роутере отключить dhcp и переключить кабель из порта WAN в порт LAN. Таким образом у вас все устройства окажутся в единой подсети 192.168.0.0/24 и проблем с доступом и маршрутизацией не будет вообще.
    Ответ написан
    3 комментария
  • Как подключиться к узлу в подсети?

    @alegzz
    перевести 2 роутер в режим точки доступа и отключить на нем dhcp. Или port forwarding настроить. Или отключить nat на втором и прописать маршруты в сеть 192.168.1.0 через 192.168.0.2
    Ответ написан
    Комментировать
  • Как заставить ImageMagick правильно воспринимать порядок файлов?

    dimonchik2013
    @dimonchik2013
    non progredi est regredi
    wincmd.ru/multirename.php это ускорение костыля

    www.imagemagick.org/Usage/files а это правила:

    используйте wildcard не "*", а ? - один символ
    т.е. вначале шуруйте все с одним, потом с двумя и т.д.

    но надежнее - переименовать
    Ответ написан
    1 комментарий
  • На каком языке лучше всего гуглить програмисту?

    djdeniro
    @djdeniro
    DeNet
    Без разницы, гугл в любом случаее смотрит и english и русскую базу
    Просто приоритетом будет тот язык, на котором делался запрос
    Ответ написан
    4 комментария
  • Есть ли интересные(обучающие) задачники по программированию (для новичка)?

    xmoonlight
    @xmoonlight
    https://sitecoder.blogspot.com
    Unity3D - моделируйте все, что хотите и есть на что посмотреть, и польза, и практика.
    Ответ написан
    Комментировать
  • Как правильно спроектировать "космический корабль"?

    Sivkoff
    @Sivkoff
    Web Developer
    Можно сделать подсистемы для модулей, типа:
    - двигательные установки;
    - оружие;
    - корпус (броня, щиты и т.д.);
    - электроника.
    А в коде уже можно обращаться к этим подсистемам в виде ship.drive.getSpeed()
    И интерфейс корабля будет меньше загроможден, и архитектура будет более гибкой.
    Ответ написан
    1 комментарий
  • Как правильно спроектировать "космический корабль"?

    Используй систему статов. Например у тебя есть класс

    enum StatType {
       speed;
       power;
       mobility;
    }
    
    class StatManager {
        // Выставляет начальное значение стата
        void setStateBase(StatType type, float value);
       // Добавляет новый модификатор для стата
        void addStatModf(StatType type, StatModf modf);
        // Удаляет модификатор стата
        void removeStatModf(StatType type, StatModf modf);
        
        // Возвращает значение стата со всеми повешенными на него StatModf 
        Float getStateValue(StatType type);
    }
    
    enum StatModfType {
       set;
       add;
       mult;
    }
    
    class StatModf {
       var StatModfType type; // как именно модификатор влияет
       var Float value;  // значение с которым он влияет
    }


    При выполнении getStateValue перебирай все модификаторы для этого стата на базовое значение.
    Рекомендую применять модификаторы в порядке их типа (StatModfType) вначале set потом mult, потом add а не в порядке добавления. Тут самый простой вариант предложен, подумай и переработай под свои нужны.
    Ответ написан
    1 комментарий
  • Как правильно спроектировать "космический корабль"?

    oshikuru
    @oshikuru
    Python-разработчик, не брезгую js / html / css
    Точно так же делаю. Не запариваюсь. Только Hardpoint назван Module xD
    Хинт: Можно кэшировать сумму показателей и пересчитывать только при поломке отсека/оборудования, либо при смене отсека/оборудования.
    Ответ написан
    Комментировать
  • Как удалить элемент списка в цикле (C#)?

    DmitryITWorksMakarov
    @DmitryITWorksMakarov
    foreach тут в любом случае не подходит

    посмотрите вот тут например.....несколько реализаций задачи подходящей под ваше описание (правда не все корректные =)
    Ответ написан
    1 комментарий