• Какие плюсы и минусы у Task и Thread?

    @Farawa
    По сути таск это пул потоков, за которыми не нужно особо следить и ими легче пользоваться, а так же они могут возвращать значения. Их можно использовать, например для запросов на сервер, для разрузки основного потока - например что-то сложное посчитать. Thread то быстрее, но task дает больше возможностей и меньше внимания к себе
    Ответ написан
    3 комментария
  • Try and Finally - Что вернет функция?

    vabka
    @vabka Куратор тега .NET
    Токсичный шарпист
    Твой код не скомпилируется :)
    Нельзя в блок finally пихать return.
    https://docs.microsoft.com/en-us/dotnet/csharp/mis...

    А так вообще да - finally выполняется в любом случае, хоть выпало хоть не выпало исключение.
    Ответ написан
    2 комментария
  • Try and Finally - Что вернет функция?

    HemulGM
    @HemulGM
    Delphi Developer, сис. админ
    finally выполнится в любом случае. В этом его смысл
    Читай документацию
    Ответ написан
    6 комментариев
  • Я сделал Code Review, может быть я где-то ошибся или у вас есть что добавить?

    @achird
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    
    //EXTERNAL CODE
    //Приведен только для справки, никак нельзя менять, код обфусцирован, исходников нет
    public sealed class ExternalDataProvider : IDisposable
    {
        public extern int LongRunningCalculation(int value, int value2);
        public extern void Dispose();
    }
    
    /// <summary>
    /// Объект-значение
    /// <para>Базовый класс</para>
    /// </summary>
    public abstract class ValueObject<T> where T : ValueObject<T>
    {
        public static bool operator ==(ValueObject<T> value1, ValueObject<T> value2)
        {
            if ((object)value1 == null)
                return (object)value2 == null;
    
            return value1.Equals(value2);
        }
    
        public static bool operator !=(ValueObject<T> value1, ValueObject<T> value2)
        {
            return !(value1 == value2);
        }
    
        public override bool Equals(object obj)
        {
            var valueObject = obj as T;
    
            if (ReferenceEquals(valueObject, null))
                return false;
    
            return CompareValues(valueObject);
        }
    
        public override int GetHashCode()
        {
            return GetValueHashCode();
        }
    
        /// <summary>
        /// Получить HashCode
        /// </summary>
        /// <returns></returns>
        protected abstract int GetValueHashCode();
    
        /// <summary>
        /// Сравнить значения
        /// </summary>
        /// <returns></returns>
        protected abstract bool CompareValues(T other);
    }
    
    /// <summary>
    /// Параметр для DataProvider
    /// </summary>
    public class Parameter : ValueObject<Parameter>
    {
        private Parameter()
        {
            FirstValue = -1;
            SecondValue = -1;
        }
        public Parameter(int firstValue, int secondValue)
        {
            if (firstValue > 100 || firstValue < 0 || secondValue < 1 || secondValue > 12)
                throw new ArgumentException("Is not supported values");
            FirstValue = firstValue;
            SecondValue = secondValue;
        }
        /// <summary>
        /// Первый параметр
        /// </summary>
        public int FirstValue { get; }
        /// <summary>
        /// Второй параметр
        /// </summary>
        public int SecondValue { get; }
    
        /// <summary>
        /// Default value
        /// </summary>
        public static readonly Parameter Empty = new Parameter();
        protected override bool CompareValues(Parameter other)
        {
            return FirstValue == other.FirstValue && SecondValue == other.SecondValue;
        }
        protected override int GetValueHashCode()
        {
            return (FirstValue, SecondValue).GetHashCode();
        }
    }
    
    /// <summary>
    /// Результат для DataProvider
    /// </summary>
    public class Result : ValueObject<Result>
    {
        private Result()
        {
            // Default value
            Value = default;
        }
        public Result(int value)
        {
            Value = value;
        }
        /// <summary>
        /// Результат
        /// </summary>
        public int Value { get; }
    
        /// <summary>
        /// Default value
        /// </summary>
        public static readonly Result Empty = new Result();
        protected override bool CompareValues(Result other)
        {
            return Value == other.Value;
        }
        protected override int GetValueHashCode()
        {
            return Value.GetHashCode();
        }
    }
    
    /// <summary>
    /// Интерфейс DataProvider
    /// </summary>
    public interface IDataProvider
    {
        public Result GetResult(Parameter parameter);
    }
    
    /// <summary>
    /// Получить данные из ExternalDataProvider без кеша
    /// </summary>
    public class DataProvider : IDataProvider
    {
        public Result GetResult(Parameter parameter)
        {
            using var externalDataProvider = new ExternalDataProvider();
            return new Result (externalDataProvider.LongRunningCalculation(parameter.FirstValue, parameter.SecondValue));
        }
    }
    
    /// <summary>
    /// DataProvider с кешированием данных
    /// Реализация кеша не имеет принципиального значения 
    /// </summary>
    public class CacheDataProvider : IDataProvider
    {
        private readonly IDataProvider dataProvider;
        private readonly ConcurrentDictionary<Parameter, Result> cache = new();
        public CacheDataProvider(IDataProvider dataProvider)
        {
            this.dataProvider = dataProvider;
        }
        public Result GetResult(Parameter parameter)
        {
            return cache.GetOrAdd(parameter, (p => dataProvider.GetResult(p)));
        }
    }


    Реализация доступа к DataProvider с использованием ValueObject для параметра и результата. Доступ к данным осуществляется через интерфейс IDataProvider. Реализация кеширования данных через декоратор. Для рабочего кода можно сделать GetResultAsync.
    Ответ написан
    Комментировать
  • Дорого ли обходиться использовавние lock, зачем делать Singleton with double check locking?

    @AndromedaStar
    .Net - monkey
    lock - это супер дешевая операция. Открытие/закрытие мьютекса - 25 нс. Боюсь, что проверка на null-pointer дороже обходится, но это интересный вопрос. Если вы выясните этот вопрос, что быстрее - будет прикольно узнать.
    Но в контексте вашего вопроса траты на lock абсолютно смехотворны, так как затраты будут 50 - 100 нс. Это сравнимо с доступом к RAM.
    Да, кстати, я часто сталкивался на собесах, что люди думают, что мьютекс реализован как-то программно на уровне ОС или вообще какая-то магия происходит в виртуальной машине. Но нет, это реализовано прямо на уровне железа, поэтому это настолько быстро.
    Ответ написан
    Комментировать
  • Дорого ли обходиться использовавние lock, зачем делать Singleton with double check locking?

    vabka
    @vabka Куратор тега .NET
    Токсичный шарпист
    зачем делать Singleton with double check locking

    Синглтон имеет смысл делать только тогда, когда (все три):
    1. Не факт, что за время работы приложения, понадобится экземпляр этого класса (иначе разруливаем через обычный static)
    2. Создавать его очень дорого, и его экземпляр требует много ресурсов (памяти, или может каких-то неуправляемых), по тому его нужно ещё и переиспользовать везде. (иначе зачем в принципе синглтон?)
    3. Нет возможности разрулить это на уровне Dependency Injection (иначе разруливаем через DI)

    Double check-lock необходим, чтобы гарантировать, что экземпляр синглтона будет создан только 1.
    Считается, что создавать экземпляр синглтона дороже, чем 1 лок.
    А проверка перед локом нужна затем, чтобы не блокировать лишний раз.
    сказали что lock это одна из самых дешевых оперций по синхронизации.

    Да, это так. Если гораздо более дорогие операции.

    get
                {
                      lock (Loker)
                      {
                            // only one check and everything is fine :)
                          if (_instance == null)
                          {
                              _instance = new Singleton1();
                          }
                    }
    
                    return _instance;
                }

    А зачем тебе Lock, если ты не собираешься изменять переменную?
    Сначала проверяешь на null, чтобы проверить, придётся ли тебе её менять.
    Потом поднимаешь lock и проверяешь снова, чтобы гарантировать, что ты один обращаешься.
    Для чтения lock не нужен.
    Проверка на null - гораздо дешевле, чем lock, по тому перед поднятием блокировки есть смысл проверить на null
    Ответ написан
  • Я сделал Code Review, может быть я где-то ошибся или у вас есть что добавить?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    Почему никто не спрашивает, что вообще делает class2 ? Т е что бы написать хороший ревью, надо хорошо понимать контекст использования этого кода. В остальном согласен с тем, что уже написали. Код писал студент-недоучка, а ревью - мидл, который не сумел изложить свои мысли. (уж простите, ничего личного). Я честно пытался разобрать что бы делал, прочитав такое ревью на свой код, и осознал что не могу понять примерно половину. Разумеется, в ревью надо объяснять всё как можно подробнее и с учётом того, кто будет читать. Если человек такой код написал, то очевидно, уровень подробностей должен быть максимальным. Более того, наверное имеет смысл сначала указать на главные ошибки, пусть он их исправит, а уже на втором ревью, в случае если он не насажает новых, что весьма и весьма вероятно, писать про имена переменных и код-стайл.
    Ну это мой подход. Конкретный интервьюер вполне может его и не разделять. Может у них "галера" и наличие даже одного "подхода" ревьюера - это роскошь. Так что вполне могу допустить, посчитали что "завалил", потому что и сами не в курсе как им оно надо.
    Ответ написан
    Комментировать
  • Я сделал Code Review, может быть я где-то ошибся или у вас есть что добавить?

    @AndromedaStar
    .Net - monkey
    Странно, что никто не сказал, но тут самая большая проблема в русском языке. Ну серьезно, каждый может ошибаться, писать не всегда грамотно, но тут просто непозволительно ужасный текст. Я понимаю, что может для человека русский не родной язык, но тогда можно написать на английском.
    Ответ написан
    2 комментария
  • Какую проблему признан решать интерфейс IDisposable?

    vabka
    @vabka Куратор тега .NET
    Токсичный шарпист
    tl;dr; Чтобы дать интерфейс для явного освобождение какого-нибудь ресурса, как правило - неуправляемого.
    Цитата из документации

    В основном этот интерфейс используется для высвобождения неуправляемых ресурсов. Сборщик мусора автоматически освобождает память, выделенную управляемому объекту, если этот объект больше не используется. Однако невозможно предсказать, когда произойдет сборка мусора. Более того, сборщик мусора не имеет сведений о неуправляемых ресурсах, таких как дескрипторы окон, или открытых файлах и потоках.
    Используйте Dispose метод этого интерфейса для явного освобождения неуправляемых ресурсов в сочетании с сборщиком мусора. Потребитель объекта может вызвать этот метод, если объект больше не нужен.
    Ответ написан
    Комментировать
  • Я сделал Code Review, может быть я где-то ошибся или у вас есть что добавить?

    @Sing303
    Опишу, как бы комментировал я
    public sealed class DataProvider : IDisposable
    {
        // nit: Предложил бы названия firstValue, secondValue либо более осмысленные, если возможно
        public extern int LongRunningCalculation(int value, int value2);
        public extern void Dispose();
    }
    
    // nit: сразу бы хотелось видеть уровень доступа и sealed (если класс не планируется наследовать)
    // Class2 - дать нормальное имя
    // { - перенести на 2ю строку по рекомендациям code style от microsoft (если не принято иных)
    class Class2 {
        // Синхронизация не нужна, если убрать метод Init, а Create вызвать в статическом конструкторе
        private readonly object _sync = new object();
        
        // _ht - дать осмысленное название
        // Судя по использованию, value может быть int`ом. Не зачем иметь лишний boxing и проверки на тип
        // _ht статический, значит к нему могут быть обращения из разных потоков, лучше сделать его ConcurrentDictionary
        // Прям сходу не могу сказать, но, возможно, использовал бы какой то другой тип Dictionary <key, key, val> (самописный или существующий), кажется, так было бы быстрее чем массив в ключе
        private static Dictionary<int[], object> _ht; 
    
        // nit: хотелось бы имена со смыслом
        public int GetValue(int index, int index2)
        {
            // Лишний метод, удалить. Create вызовем в static конструкторе
            Init();
            // Если ключ у нас объект, то необходимо реализовать IEqualityComparer для этого Dictionary (иначе не понятно как по нему искать)
            var key = new[] {index, index2};
            // Проверка на тип не нужна, Dictionary сделаем типа int
            if (_ht.ContainsKey(key) & _ht[key].GetType() == typeof(int))
                // приведение типов больше не нужно
                return ((int)_ht[key]);
            // nit: else не обязателен
            else
                // int не может быть null, будет ошибка, вернуть либо default, либо возвращаемое значение должно быть int?
                return null;
        }
    
        // Метод удалить, вызовем Create в статическом конструкторе без lock
        public void Init() 
        {
            if (_ht == null)
                lock (_sync)
                    Create();
        }
        
        // Нет смысла делать метод public, сделать private
        public static void Create() 
        {
            // nit: и так видно какой тип создаём, можно использовать var
            // Обернуть в using
            DataProvider provider = new DataProvider();
            
            // Тут следует инициализировать значение _ht, т.к. ранее оно нигде не создаётся
            // Не забыть передать реализацию IEqualityComparer в конструктор
            
            // nit: хотелось бы видеть использование фигурных скобок (если не принят иной code style)
            // nit: вместо int можно var
            // i и j, похоже, несут какой то смысл, можно попробовать придумать нормальное название (иначе не понятно почему 100 и 12, их можно в константы класса)
            // nit: возможно можно использовать Parallel.ForEach
            for (int i = 0; i < 100; i++)
                for (int j = 1; j <= 12; j++)
                    _ht[new [] { i, j }] = provider.LongRunningCalculation(i, j);
        }
    }

    А переписал бы так (если не убирать массив в dictionary)
    public interface IDataProvider : IDisposable
    {
        int LongRunningCalculation(int firstValue, int secondValue);
    }
    
    public sealed class DataProvider : IDataProvider
    {
        public extern int LongRunningCalculation(int firstValue, int secondValue);
        public extern void Dispose();
    }
    
    public sealed class DataProviderService
    {
        public DataProviderService(IDataProvider dataProvider)
        {
            _dataProvider = dataProvider;
        }
    
        private static readonly ConcurrentDictionary<int[], int?> _calculatedCache = new ConcurrentDictionary<int[], int?>(new CalculatedEqualityComparer());
        private readonly IDataProvider _dataProvider;
    
        public int? GetValue(int firstValue, int secondValue)
        {
            var isNotSupportedValues = firstValue > 100 || firstValue < 0 || secondValue < 1 || secondValue > 12;
            if (isNotSupportedValues)
            {
                return null;
            }
    
            var key = new[] { firstValue, secondValue };
            if (!_calculatedCache.TryGetValue(key, out var result))
            {
                result = _dataProvider.LongRunningCalculation(firstValue, secondValue);
                _calculatedCache.TryAdd(key, result);
            }
            
            return result;
        }
    }
    Ответ написан
    5 комментариев
  • Я сделал Code Review, может быть я где-то ошибся или у вас есть что добавить?

    insighter
    @insighter
    -First time? - Huh? (C#, React, JS)
    Основная задача код-ревью дать обратную связь на выполненную работу, а не написать сочинение "по мотивам".
    Ваши комментарии это не код-ревью, особенно для уровня кандидата которого они ищут.

    PS Два момента непонятны.
    1.
    public extern int LongRunningCalculation(int value, int value2);

    Какая семантика у ключевого слова extern в этом случае, подскажет кто?

    2. На ревью дается то, что компилируется.
    public int GetValue(int index, int index2)

    При компиляции выдаст ошибку на строке return null;

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

    PS Ах да судя по инициализации словаря, вообще непонятно зачем он используется, когда нужен двухмерный массив.
    Ответ написан
    4 комментария
  • Linux или Windows для C++ разработчика?

    @hauptling
    под windows более актуально все-таки c#
    Ответ написан
    2 комментария
  • Какие отличие между значимыми и ссылочными типами? Зачем придумали такое разделение? Нельзя было придумать только либо значимые либо ссылочные?

    @Myclass
    ответ кроется в самой сущности. Сохранить переменную byte, int, double word или адресс - для этого понадобиться всего-то навсего байт, два байта, ну или столько, сколько на сегодня актуально - например 8 байтов (64 Bit).
    Это всегда более менее легко организовать. Например тот-же int array с его элементами. Они все чинно лежат друг за другом. Если идёт разговор о сложных структурах, начиная со string, то там уже проще сохранять и организовывать адресса для тех мест, где на самом деле лежат эти структуры.

    И всё - нет никакого злого умысла или тупости. Всё сделано для простоты организации всех этих вещей и легкости справлятся с такими задачами, как создавание переменных/обьектов, их видоизменения и удаления.

    Так-же как и с Carbadge Collection. Тратить время на "точное" удаление обьектов из памяти во время работы программы - свою программу не уважать. Но здесь распределение действий, а в вашем вопросе распределение мест.
    Ответ написан
    8 комментариев
  • Какие отличие между значимыми и ссылочными типами? Зачем придумали такое разделение? Нельзя было придумать только либо значимые либо ссылочные?

    insighter
    @insighter
    -First time? - Huh? (C#, React, JS)
    Все хранить в стеке невозможно для обычных программ.
    Все хранить в куче реально (достаточно упаковывать все valued-переменные), но очень и очень не оптимально. Работа со стеком гораздо быстрее, для работы с ним есть специализированные регистры процессора, а для того чтобы обратится к участку произвольной памяти компьютера даже на низком уровне надо сделать много операций. И очищается стек моментально, никаких сборщиков мусора не нужно.
    Ответ написан
  • Достоинства и недостатки ООП более детально?

    kinglostov
    @kinglostov
    просто lostov
    Идеи ООП (Хоар, 1966, “Совместное использование кода”):
    • Инкапсуляция (объединение данных и действий над ними, или для каждого типа данных – свои функции-действия);
    • Наследование (модификация развития программы за счет надстроек; вместо изменения написаного кода – делаем над ним надстройки);
    • Организация взаимодействия между объектами; перенесение взаимодействия объектов из физического мира в программирование.
    Два вида взаимодействия:
    1. Акцессорное – вступление в контакт, получение информации от объектов (синхронное взаимодействие)
    2. Событийное взаимодействие – взаимодействие, связанное с изменением состояния объекта (асинхронное взаимодействие)
    Объект – конкретная реализация абстрактного типа, обладающий характеристиками состояния, поведения, индивидуальности.

    Состояние – один из возможных вариантов условий существований объекта.

    Поведение – описание объекта в терминах изменения его состояния и передача сообщений (данных) в процессе воздействия.

    Индивидуальность – сущность объекта, отличающееся от других объектов.

    Действие – деятельность или операция, которые должны быть выполнены над объектом.

    Модель Мура:
    • Состоит из множества состояний, каждое состояние представляет стадию в жизненном цикле типичного экземпляра.
    • Из множества событий: каждое событие представляет собой инцидент или указание на то, что происходит эволюционирование.
    • Из (множества) правил перехода определяет какое новое состояние получает в следствие какого-нибудь события (событие может и не изменять объект)
    • Из действий – деятельность или операция который должен быть выполнены над объектом чтобы он мог достичь состояния (каждому действию соответствует состояние).
    Категории объектов:
    • Реальные объекты – абстракция фактического существующего объекта реального мира.
    • Роли – абстракции цели или назначения человека, части оборудования или организации.
    • Инциденты – абстракция чего-то происшедшего или случившегося (наводнение, скачёк напряжения, выборы). -
    • Взаимодействия – объекты получаемые из отношений между другими объектами (перекресток, договор, взятка). -
    • Спецификации – используется для представления правил, критериев качества, стандартов (правила дорожного движения, распорядок дня).
    Преимущества ООП:
    • Возможность легкой модификации (при грамотном анализе и проектировании)
    • Возможность отката при наличии версий
    • Более легкая расширяемость
    • «Более естественная» декомпозиция программного обеспечения, которая существенно облегчает его разработку.
    • Сокращение количества межмодульных вызовов и уменьшение объемов информации, передаваемой между модулями.
    • Увеличивается показатель повторного использования кода.
    Недостатки ООП:
    • Требуется другая квалификация
    • Резко увеличивается время на анализ и проектирование систем
    • Увеличение времени выполнения
    • Размер кода увеличивается :interrobang:
    • Неэффективно с точки зрения памяти (мертвый код - тот, который не используется) :interrobang:
    • Сложность распределения работ на начальном этапе
    • Себестоимость больше
    Ответ написан
    1 комментарий
  • Как сервер передает страницы?

    Zoominger
    @Zoominger
    System Integrator
    Да, по протоколу HTTP/HTTPS, и, как правило, в виде HTML. Бройзер делает GET-запрос и получает данные.
    Так же передаются по тому же HTML вспомогательные файлы - CSS, JS-скрипты, картиночки.
    Ответ написан
    2 комментария