private static float LotSize = 100000f;     // const - нигде не меняется и дальше этого класса не прорастает, + название поле должно быть lower-case

        // перегружен обязанностями, как метод, так и класс нарушают принцип единственной ответственности
        public void HandleTrades(Stream stream)
        {
            #region Обязанность для класса, который работает с файлами

            /*
             * можно вынести в статический класс и передавать путь к файлу:
             * + : не привязываемся к конкретному файлу
             * - : может поменяться тип хранилища, например на бд
             * либо создать репозиторий
             * + : гибкость относительно типа хранилища
             * - : объект класса хранилища заточенный только для работы с ним (не очень удобно в контексте файлов)
             */
            var lines = new List <string>();

            using (var reader = new StreamReader(stream))   // отдельный метод для чтения
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    lines.Add(line);
                }
            }
            #endregion

            #region Необходимо выделить в отдельную сущность для создания Trade на основе строк

            /*
             * Решение: создать класс маппера для trade - позволит добавлять новые методы для маппинг на(с) разные сущности
             */
            var trades = new List <TradeRecord>();

            var lineCount = 1;
            foreach (var line in lines)
            {
                var fields = line.Split(new char[] { ',' });

                #region Ответственность логировщика и валидатора

                /*
                 * Решение: использовать NLog (гибкий и легконастраиваемый)
                 * валидация полученных данных будет ответственностью маппера - в зависимости от сущностей, с которых маппим, можно менять правила
                 */
                if (fields.Length != 3)  // const!
                {
                    System.Console.WriteLine("WARN: Line {0} malformed. Only {1} field(s) found.", lineCount, fields.Length);
                    continue;
                }

                if (fields[0].Length != 6)   // const!
                {
                    System.Console.WriteLine("WARN: Trade currencies on line {0} malformed: '{1}'", lineCount, fields[0]);
                    continue;
                }

                if (!int.TryParse(fields[1], out var tradeAmount))
                {
                    System.Console.WriteLine("WARN: Trade amount on line {0} not a valid integer: '{1}'", lineCount, fields[1]);
                }

                if (!decimal.TryParse(fields[2], out var tradePrice))
                {
                    System.Console.WriteLine("WARN: Trade price on line {0} not a valid decimal: '{1}'", lineCount, fields[2]);
                }
                #endregion

                var sourceCurrencyCode      = fields[0].Substring(0, 3); // const 3
                var destinationCurrencyCode = fields[0].Substring(3, 3); // const 3

                var trade = new TradeRecord
                {
                    SourceCurrency      = sourceCurrencyCode,
                    DestinationCurrency = destinationCurrencyCode,
                    Lots  = tradeAmount / LotSize,
                    Price = tradePrice
                };

                trades.Add(trade);

                lineCount++;
            }
            #endregion

            #region Обязанность класса, который взаимодействет с бд

            /*
             * Решение создать класс репозитория - исключит зависимость от базы данных
             */
            string connectionString = ConfigurationManager.ConnectionStrings["TradeData"].ConnectionString; // передаётся во время создания репозитория

            /*
             * последующий код в scope мне совершенно не нравиться: мы в одном месте открываем соединение с бд, пишем в бд и сохраняем
             * но у меня нет идей как это можно аккуратно исправить
             */
            using (var connection = new SqlConnection(connectionString))
            {
                connection.Open();

                // отдельный метод
                using (var transaction = connection.BeginTransaction())
                {
                    foreach (var trade in trades)
                    {
                        // отдельный метод
                        var command = connection.CreateCommand();
                        command.Transaction = transaction;
                        command.CommandType = System.Data.CommandType.StoredProcedure;
                        command.CommandText = "dbo.Insert_Trade";
                        command.Parameters.AddWithValue("@sourceCurrency", trade.SourceCurrency);
                        command.Parameters.AddWithValue("@destinationCurrency", trade.DestinationCurrency);
                        command.Parameters.AddWithValue("@lots", trade.Lots);
                        command.Parameters.AddWithValue("@price", trade.Price);

                        command.ExecuteNonQuery();
                    }

                    transaction.Commit();
                }
                connection.Close();
            }
            #endregion

            System.Console.WriteLine("INFO: {0} trades processed", trades.Count); // logger
        }
        public void HandleTrades(Stream stream)
        {
            var lines = new List <string>();

            using (var reader = new StreamReader(stream))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    lines.Add(line);
                }
            }

            var trades = new List <TradeRecord>();

            var lineCount = 1;

            foreach (var line in lines)
            {
                var fields = line.Split(new char[] { ',' });

                if (fields.Length != 3)
                {
                    System.Console.WriteLine("WARN: Line {0} malformed. Only {1} field(s) found.", lineCount, fields.Length);
                    continue;
                }

                if (fields[0].Length != 6)
                {
                    System.Console.WriteLine("WARN: Trade currencies on line {0} malformed: '{1}'", lineCount, fields[0]);
                    continue;
                }

                if (!int.TryParse(fields[1], out var tradeAmount))
                {
                    System.Console.WriteLine("WARN: Trade amount on line {0} not a valid integer: '{1}'", lineCount, fields[1]);
                }

                if (!decimal.TryParse(fields[2], out var tradePrice))
                {
                    System.Console.WriteLine("WARN: Trade price on line {0} not a valid decimal: '{1}'", lineCount, fields[2]);
                }

                var sourceCurrencyCode      = fields[0].Substring(0, 3);
                var destinationCurrencyCode = fields[0].Substring(3, 3);

                var trade = new TradeRecord
                {
                    SourceCurrency      = sourceCurrencyCode,
                    DestinationCurrency = destinationCurrencyCode,
                    Lots  = tradeAmount / LotSize,
                    Price = tradePrice
                };

                trades.Add(trade);

                lineCount++;
            }

            // save into database
            string connectionString = ConfigurationManager.ConnectionStrings["TradeData"].ConnectionString;

            using (var connection = new SqlConnection(connectionString))
            {
                connection.Open();
                using (var transaction = connection.BeginTransaction())
                {
                    foreach (var trade in trades)
                    {
                        var command = connection.CreateCommand();
                        command.Transaction = transaction;
                        command.CommandType = System.Data.CommandType.StoredProcedure;
                        command.CommandText = "dbo.Insert_Trade";
                        command.Parameters.AddWithValue("@sourceCurrency", trade.SourceCurrency);
                        command.Parameters.AddWithValue("@destinationCurrency", trade.DestinationCurrency);
                        command.Parameters.AddWithValue("@lots", trade.Lots);
                        command.Parameters.AddWithValue("@price", trade.Price);

                        command.ExecuteNonQuery();
                    }

                    transaction.Commit();
                }
                connection.Close();
            }

            System.Console.WriteLine("INFO: {0} trades processed", trades.Count);
        }