Визитная карточка:
https://nemiro.developer.cards

Решения для .NET:
www.nemiro.net

Архив примеров для программистов:
https://github.com/alekseynemiro/examples

Достижения

Все достижения (20)

Наибольший вклад в теги

Все теги (55)

Лучшие ответы пользователя

Все ответы (259)
  • Как научиться писать код быстро?

    AlekseyNemiro
    @AlekseyNemiro
    ответ помог - отметь решением, нет - будет удалён
    Методика есть и она стара как мир:

    Семь раз подумай, один раз напиши.
    Чем меньше напишешь, тем меньше будет работы.

    А каким образом осуществлять мыслительный процесс - это вам виднее :-)

    Учитесь выносить обдумывание на задний план, так сказать в фоновый режим, чтобы мозг сам думал, а вы могли заниматься чем-то другим. В особенности это касается сложных задач. Сложные задачи где-то в глубинах мозга решаются быстрее. Каким образом развивать этот навык, не могу точно сказать, все само как-то получается. Но однозначно можно утверждать, что нужно чаще думать :-)

    Что касается механики, то быстро вводить код - это не то, к чему стоит стремиться, конечно если целью не является желание стать секретаршей :-)
    Ответ написан
  • Что за страности в Stream в.NET?

    AlekseyNemiro
    @AlekseyNemiro
    ответ помог - отметь решением, нет - будет удалён
    ReadByte возвращает тип int, т.к. при достижении конца будет возвращено значение минус один. А тип byte может иметь значение в диапазоне от нуля до 255. То есть, считывая байты, сообщить о достижении конца потока при помощи типа byte невозможно (байт, имеющий значение ноль может быть полезным байтом), поэтому используется тип int.

    Метод Read принимает буфер, в который будут помещены считанные данные. Буфер - это массив байт. Изначально он должен быть пустым. Размер массива - по своему смотрению. Чем больше размер буфера, тем больше данных будет помещено в память, меньше проделано операций.

    Метод Read возвращает число помещенных в буфер байт. Ноль - достигнут конец потока.

    FileInfo f = new FileInfo(@"C:\example.dat");
    using (FileStream fs = f.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    {
     using (BinaryReader br = new BinaryReader(fs))
     {
       int bytesRead = 0;
       byte[] buffer = new byte[256]; // размер буфера 256 единиц байт
       StringBuilder result = new StringBuilder();
       while ((bytesRead = br.Read(buffer, 0, buffer.Length)) != 0) // читаем не более 256 единиц байт в buffer
       {
         // из buffer следует извлекать не более bytesRead (в конце это число может быть меньше 255)
       }
     }
    }

    Массивы являются ссылочными типами и нет необходимости использовать out.
    Ответ написан
  • Какие требования у.NET при стандартной сериализации?

    AlekseyNemiro
    @AlekseyNemiro
    ответ помог - отметь решением, нет - будет удалён
    Чтобы класс можно было сериализовать, необходимо пометить его атрибутом [Serializable].
    [Serializable]
    public class MyClass 
    {
    }

    Атрибут [Serializable] также должны иметь все типы, которые включены в класс. Если у какого-то из типов не будет этого атрибута, то при попытке выполнить сериализацию, возникнет исключение. Это минимум, что необходимо.

    Для двоичной сериализации используется класс BinaryFormatter.
    // данные, которые будем сериализовать
    var data = new List<int> { 1, 2, 3 };
    
    // выполняем сериализацию 
    // в MemoryStream (можно в любой Stream)
    var bf = new BinaryFormatter();
    var m = new MemoryStream();
    bf.Serialize(m, data);
                
    // курсор потока переводим в начало, т.к. мы работали с потоком выше
    // если открывать новый поток, то это делать не обязательно
    m.Position = 0;
    // выполняем десериализацию данных из MemoryStream
    var result = (List<int>)bf.Deserialize(m);
    
    // выводим результат в консоль
    result.ForEach(itm => Console.WriteLine(itm));


    Если в объекте попадется тип, который не помечен атрибутом [Serializable], то можно реализовать в классе интерфейс ISerializable. Либо сделать для этого типа отдельный класс, реализующий интерфейс ISerializable. При этом, не забывая про атрибут [Serializable], который обязательно должен присутствовать.

    При реализации интерфейса ISerializable, в классе нужно определит метод GetObjectData, который будет подготавливать данные для сериализации. А также реализовать перегрузку конструктора для принятия сериализованных данных.
    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
      if (info == null)
      {
        throw new ArgumentNullException("info");
      }
      info.AddValue("Ключ", "Значение");
      info.AddValue("Ключ2", this.ИмяСвойства); 
      // и т.д.
    }
    
    // конструктор
    protected ИмяКласса(SerializationInfo info, StreamingContext context)
    {
      if (info == null)
      {
        throw new ArgumentNullException("info");
      }
      this.Свойство = info.GetValue("Ключ", typeof(типДанных));
      this.ИмяСвойства = (string)info.GetValue("Ключ2", typeof(string));
      // и т.д.
    }

    Часто спрашивают, как сериализовать Dictionary<TKey, TValue>. На основе всего выше изложенного, можно сделать вот такой класс:
    [Serializable]
    public class MyDictionary : Dictionary<string, object>, ISerializable
    {
    
      public MyDictionary() { }
    
      protected MyDictionary(SerializationInfo info, StreamingContext context)
      {
        if (info == null)
        {
          throw new ArgumentNullException("info");
        }
        int count = info.GetInt32("Count"); // получаем число элементов
        for (int i = 0; i < count; i++) // перебираем элементы
        {
          // получаем ключ и значение по индексу элемента
          string key = info.GetString(String.Format("ItemKey{0}", i));
          object value = info.GetValue(String.Format("ItemValue{0}", i), typeof(object));
          // добавляем элемент в себя
          this.Add(key, value);
        }
      }
    
      public void GetObjectData(SerializationInfo info, StreamingContext context)
      {
        if (info == null)
        {
          throw new ArgumentNullException("info");
        }
        // перебираем все элементы коллекции
        int i = 0;
        foreach (KeyValuePair<string, object> item in this)
        {
          // добавляем отдельно ключ и значение
          info.AddValue(String.Format("ItemKey{0}", i), item.Key, typeof(string));
          info.AddValue(String.Format("ItemValue{0}", i), item.Value);
          i++;
        }
        // запоминаем, сколько всего элементов
        info.AddValue("Count", this.Count);
      }
    }

    Пример использования:
    // выполняем сериализацию коллекции
    var data = new MyDictionary();
    data.Add("Key", "Value");
    data.Add("Key2", "Value2");
    data.Add("Key3", 123);
    
    var bf = new BinaryFormatter();
    var m = new MemoryStream();
    bf.Serialize(m, data);
    
    // выполняем десериализацию
    m.Position = 0;
    var result = (MyDictionary)bf.Deserialize(m);
    
    // выводим результат
    foreach (var item in result)
    {
      Console.WriteLine("{0} = {1}", item.Key, item.Value);
    }

    Посмотреть в .NET Fiddle, как это работает.
    Ответ написан
  • Стоит ли учиться писать скрипты на bash?

    AlekseyNemiro
    @AlekseyNemiro
    ответ помог - отметь решением, нет - будет удалён
    Конечно стоит изучать bash. В системах Linux многое на нем сделано, так что в любом случае придется с ним сталкиваться.

    Я не учил bash намеренно. В какой-то момент просто взял и начал на нем писать код :-) Могу сказать, что язык ужасный, привередливый, местами крайне неудобный, перенасыщен подводными камнями (точнее морским ежами и минами). Но в то же время bash достаточно мощный язык.

    Для небольших скриптов будет проще использовать bash. Для чего-то сложного лучше использовать нормальный язык программирования.

    Для понимания основ будет достаточно хороших знаний и опыта работы с любым другим языком программирования; это поможет задавать правильные вопросы и быстро находить ответы.

    В основе идеологии Unix-подобных систем лежит простота. Так что с чем-то сложным скорее всего придется сталкиваться редко. Знаний программирования или даже основ программирования, должно вполне хватить для понимания скриптов bash, с которыми придется сталкиваться. Но пару недель его хорошенько поковырять, лишним не будет, главное мотивацию найти.
    Ответ написан
  • В чём польза readonly полей в C#?

    AlekseyNemiro
    @AlekseyNemiro
    ответ помог - отметь решением, нет - будет удалён
    Значения полей readonly можно менять динамически, в конструкторе класса. Последующие изменения невозможны.

    public class MyClass
    {
    
      public readonly int Value = 0;
    
      public MyClass()
      {
        this.Value = 123;
      }
    
    }


    Для чего это использовать - зависит от фантазии.

    Например, можно создать класс User и сделать readonly поле, содержащее идентификатор пользователя. Таким образом, идентификатор пользователя можно будет указать только при инициализации класса и, в последующем, изменить его будет невозможно. Это позволит избежать проблем в логике, которые еще предстоит придумать :-)

    Если сравнивать со свойствами и константами, то значения readonly свойств могут меняться в процессе жизненного цикла класса. Значения readonly полей, как уже было сказано ранее, можно указывать только при объявлении и в конструкторе класса.

    Значения констант являются фиксированными и изменять их программно невозможно. Количество типов для констант ограничено, в то время как поля могут иметь любой тип. Константы являются статическими, а поля не обязаны быть таковыми. В этом плане, readonly поля более гибкие, чем константы.

    В дополнение, немного кода (Console Application):
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Net;
    using System.Timers;
    using System.Threading;
    
    namespace ConsoleApplication20
    {
    
      class Program
      {
        static void Main(string[] args)
        {
          // создаем экземпляр класса
          var t = new Toster(199065);
          // выводим значение константы ProjectName
          // доступ только через Toster
          Console.WriteLine(Toster.ProjectName);
          // доступа к локальным константам здесь нет
          // Toster.CounterPattern
          // t.CounterPattern
    
          // выводим заголовок вопроса
          Console.WriteLine(t.Title);
    
          // бесконечность - не предел!
          while (true)
          {
            // t.Id = 123;
            // мы не можем поменять идентификатор
            // следовательно, этот код, логически, будет работать правильно
    
            // выводим число ответов
            Console.WriteLine("Ответов: {0}", t.AnswersCount);
    
            // t.AnswersCount = 123
            // мы не можем менять значение readonly свойства,
            // но оно может меняться внутри экземпляра класса
    
            // пауза 10 сек.
            Thread.Sleep(10000);
          }
        }
      }
    
      public class Toster
      {
    
        // публичная константа, доступ через Toster
        public const string ProjectName = "Тостер";
    
        // локальная константа, доступна только в рамках этого класса
        const string CounterPattern = "<span class=\"section-header__counter\" role=\"answers_counter\">";
    
        // публичные поля только для чтения
        // значение может быть установлено в конструкторе
        public readonly string Title = "Нет данных";
        public readonly int Id = 0;
        
        // свойство только для чтения
        // значение может меняться в процессе жизни экземпляра класса
        // при помощи локальной переменной
        private int _AnswersCount = 0;
        public int AnswersCount
        {
          get
          {
            return _AnswersCount;
          }
        }
    
        // это просто таймер
        private System.Timers.Timer Timer = null;
    
        // а это конструктор<s>, но не Lego</s>
        public Toster(int id)
        {
          if (id <= 0) { return; }
          
          // получаем вопрос
          var web = new WebClient();
          web.Encoding = Encoding.UTF8;
          var result = web.DownloadString(String.Format("https://toster.ru/q/{0}", id));
          // из шаблона url тоже можно сделать константу
          // либо в классе можно сделать readonly свойство, 
          // которое будет на лету формировать итоговый адрес:
          // return String.Format("https://toster.ru/q/{0}", this.Id)
    
          // устанавливаем значения для полей
          this.Id = id;
          this.Title = WebUtility.HtmlDecode
          ( 
            result.Substring
            (
              result.IndexOf("<title>") + "<title>".Length,
              result.IndexOf("</title>") - result.IndexOf("<title>") - "<title>".Length
            )
          );
          // выдергиваем число ответов на вопрос
          this.ParseAnswersCount(result);
    
          // запускаем периодическую проверку <s>Менделеева</s>
          Timer = new System.Timers.Timer(10000);
          Timer.Elapsed += Timer_Elapsed;
        }
        
        // обработчик истечения интервала времени 
        private void Timer_Elapsed(object sender, EventArgs e)
        {
          var web = new WebClient();
          web.Encoding = Encoding.UTF8;
          var result = web.DownloadString(String.Format("https://toster.ru/q/{0}", this.Id));
          this.ParseAnswersCount(result);
        }
    
        // выдергиватель количества ответов
        private void ParseAnswersCount(string value)
        {
          int startstart = value.IndexOf("Ответы на вопрос");
          int start = value.IndexOf(CounterPattern, startstart) + CounterPattern.Length;
          int len = value.IndexOf("</span>", start) - start;
          _AnswersCount = Convert.ToInt32(value.Substring(start, len));
        }
        
      }
    
    }
    Ответ написан