Ответы пользователя по тегу ASP.NET
  • Я сделал 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 комментариев
  • Я не умею готовить репозиторий или он просто не очень?

    @Sing303
    1. Писать свои методы до бесконечности (Таких методов на самом деле будет не много)
    2. Тоже писать свой метод, помещать в зависимости от того, из какой таблицы выборка (В вашем случае logs)
    3. Подключать по 1, если вам надо 15, то подключать 15 по одному, но тут скорее всего у вас явное нарушение принципа единственной ответственности. Проблем быть не должно, есть IoC контейнеры, фасад, если нужно.
    4. Lazy loading используют только там, где не критична производительность, во всех остальных случаях его отключают и получают все данные сразу
    5. Этот паттерн в первую очередь применяется для устранения дублирования кода и инкапсуляции, что является базой в ООП. Если нужен "чистый" и гибкий код, нет ничего сложного в реализации и поддержки репозитория, это очень простой паттерн, а если вам кажется сложным, значит вы его не поняли.
    Ответ написан
    3 комментария
  • Как писать тесты в asp.net mvc не затрагивая Entity Framework?

    @Sing303
    Вариант 1:
    Использовать неограниченные фреймворки, на подобии Typemock, он позволит подделывать что угодно, приватные и статические методы

    Вариант 2:
    Использовать репозиторий. Необходимость использовать Typemock говорит о том, что код "плохо пахнет" и в нём явно что-то не так.
    Ответ написан
    Комментировать