Ответы пользователя по тегу .NET
  • Как отключить encode в WebClient UploadValues?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Если параметр в Url, то можно сделать экземпляр Uri и отключить кодирование:
    var url = new Uri("http://site.com/index.php?199|&param=1", true);
    // ...
    var response = wb.UploadValues(url, "POST", data);

    Без кодирования параметров с помощью HttpClient
    using (var client = new HttpClient())
    {
      var url = new Uri("http://site.com/index.php?199|&param=1", true);
      var data = new StringBuilder();
      data.AppendLine("abc=199|");
    
      using (var content = new StringContent(data.ToString(), Encoding.UTF8, "application/x-www-form-urlencoded"))
      {
        using (var request = new HttpRequestMessage(HttpMethod.Post, url))
        {
          request.Content = content;
    
          using (var response = client.SendAsync(request).Result)
          {
            response.EnsureSuccessStatusCode();
    
            // var result = await response.Content.ReadAsStringAsync();
            var result = response.Content.ReadAsStringAsync().Result;
          }
        }
      }
    }

    Ответ написан
    3 комментария
  • Как сделать solution explorer в С#?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Какие нужны классы - зависит от задачи. Чтобы вывести список каталогов и файлов, дополнительные классы не нужны. Код может быть примерно таким:

    treeView1.Items.Clear();
    GetFiles("C:/Windows/Microsoft.NET", null);

    private void GetFiles(string path, TreeViewItem parent)
    {
      var node = new TreeViewItem() { Header = System.IO.Path.GetFileName(path) };
          
      if (parent == null)
      {
        treeView1.Items.Add(node);
      }
      else
      {
        parent.Items.Add(node);
      }
    
      var attr = System.IO.File.GetAttributes(path);
    
      if (attr.HasFlag(System.IO.FileAttributes.Directory))
      {
        var directories = System.IO.Directory.GetDirectories(path);
    
        foreach (var dir in directories)
        {
          GetFiles(dir, node);
        }
    
        var files = System.IO.Directory.GetFiles(path);
    
        foreach (var file in files)
        {
          node.Items.Add(System.IO.Path.GetFileName(file));
        }
      }
    }
    Ответ написан
    2 комментария
  • Где применяют ASP.net сегодня?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Мне интересно в какой сфере применяют ASP

    ASP - умер, да здравствует ASP.NET! А нет, да здравствует ASP.NET Core! ;-)

    1. Любые проекты. Как правильно большие и сложные. Делать что-то простое смысла нет, для этого можно использовать что-нибудь типа PHP.

    2. Работа есть. Но новичкам нынче придется не сладко. За последние семь лет все сильно усложнилось.

    3. Можно делать все :-) Блоги, формы, порталы, магазины, платежные сервисы, корпоративные сайты. В общем, все что угодно. Мои нынешние проекты являются сложными системами, которые я уже не способен охватывать целиком и они не ограничиваются использованием ASP.NET. Но .NET доминирует, поскольку это удобно и работать просто приятно, от процесса написания кода, до отладки и тестирования.
    Ответ написан
    Комментировать
  • Почему не хочет парсить string(Regex)?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    string pattern = "/(.*?)[\\/]([A-Z]*)(,.)(\".*?\")/gm";

    string pattern = "(.*?)/([A-Z]*)(,|.)(\".*?\")";
    var regex = new Regex(pattern, RegexOptions.Multiline);
    Ответ написан
    Комментировать
  • Как управлять состоянием полей обьекта через атрибуты?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Используйте BindingFlags:
    var managementsItems = this.GetType().GetMembers
    (
      BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public
    ).Where(m => Attribute.IsDefined(m, typeof(HideAttribute))).ToList();
    Ответ написан
    Комментировать
  • Как лучше сделать в MVC подобее Url.Action в аттрибуте на server side?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Перенаправление можно выполнить примерно так:

    HttpContext.Current.Response.RedirectToRoute
    (
      new 
      { 
        controller = "Home", 
        action = "Index" 
      }
    );

    Лучше сделать вспомогательный класс и соответствующие методы для этого.

    Маршруты можно найти в System.Web.Routing.RouteTable.Routes.

    Данные текущего маршрута:

    var routeData = ((System.Web.Mvc.MvcHandler)HttpContext.Current.Handler).RequestContext.RouteData;

    Сделать экземпляр UrlHelper для контекста текущего запроса можно следующим образом:

    var urlHelper = new System.Web.Mvc.UrlHelper(HttpContext.Current.Request.RequestContext);
    var url = urlHelper.Action("Index", "Home");
    Ответ написан
    Комментировать
  • Как с dll запустить диалоговое окно с браузером и получить результат?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Слишком общий вопрос :-)

    Манипулирование живым браузером - плохая идея, это ненадежно и можно споткнуться на всяких антивирусах. На уровне приложения лучше использовать компонент WebBrowser (по сути - Internet Explorer) или альтернативу (это будет минимум мегабайт 20-40 к размеру программы).

    Давным-давно писал статейку по работе с ВКонтакте, не знаю насколько сейчас актуальна и работает ли:
    Разработка desktop-приложения для «ВКонтакте» на C#

    Есть также библиотека с открытым исходным кодом:
    https://github.com/alekseynemiro/nemiro.oauth.dll

    Попробуйте выдернуть клиент для ВКонтакте (включая зависимости) или внедрить целиком, если не устроит присутствие лишней библиотеки в проекте (даже двух, если используется Windows Forms) :-)

    Готовые формы для Windows Forms:
    https://github.com/alekseynemiro/Nemiro.OAuth.Logi...

    Статья по использованию библиотеки: Авторизация по протоколу OAuth в проектах .NET Fra...

    Демонстрация ASP.NET MVC: demo-oauth.nemiro.net

    Получение адреса для авторизации делается примерно так:

    string applicationId = "идентификатор вашего приложения";
    string scope = "status,email";
    string authorizeUrl = "https://oauth.vk.com/authorize";
    authorizeUrl += String.Format("?client_id={0}&response_type=code", applicationId);
    // authorizeUrl += String.Format("&state={0}", "все что вам нужно");
    authorizeUrl += String.Format("&scope={0}", scope);

    Адрес authorizeUrl можно открыть в WebBrowser: webBrowser1.Navigate(authorizeUrl). В обработчике события DocumentCompleted можно получать код авторизации или маркер доступа (смотря какой response_type используется).

    На примере обработчика по умолчанию из моей библиотеки:

    protected internal void DefaultCallback(object sender, WebBrowserCallbackEventArgs e)
    {
      // ожидаем, когда будет получен результат
      if (e.Url.Query.IndexOf("code=") != -1 || e.Url.Query.IndexOf("oauth_verifier=") != -1)
      {
        // результат получен, извлекаем код авторизации
        // из строка параметров запроса
        // e.Url.Query // <= строка параметров запроса
        // либо oauth_verifier, либо code - точно уже не помню
      }
    }

    Но вообще, все может быть чуть сложнее. Нужно учитывать версию IE и, в идеале, использовать самую свежую (см. SetIEVersion). Вероятность появления ошибок в клиентском коде и адекватная реакция на них. Всех подводных камней сейчас и не припомню.

    Если response_type=code, как в указанном выше коде получения адрес авторизации, то конвертировать код авторизации в маркер доступа можно выполнив запрос (скорее всего POST) к странице https://oauth.vk.com/access_token, на которую нужно передать следующие параметры:

    code=полученный код
    client_id=идентификатор приложения
    client_secret=секретный ключ
    grant_type=authorization_code

    Запрос маркера доступа нужно делать без WebBrowser, а например, с помощью WebClient или HttpClient.
    Если все правильно, сервер вернет access_token.
    Ответ написан
    Комментировать
  • Как выделить строку таблицы при нажатии пр. клавиши мыши?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Добавить обработчик MouseDown:

    <DataGrid x:Name="dataGrid" MouseDown="dataGrid_MouseDown"/>

    Код обработчика примерно такой:

    private void dataGrid_MouseDown(object sender, MouseButtonEventArgs e)
    {
      if (e.RightButton == MouseButtonState.Pressed)
      {
        var row = DataGridRow.GetRowContainingElement(e.OriginalSource as FrameworkElement);
        if (row != null)
        {
          // dataGrid.SelectedIndex = row.GetIndex();
          dataGrid.SelectedItem = row;
        }
      }
    }
    Ответ написан
    Комментировать
  • Заняты ли потоки при использовании async/await?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    https://msdn.microsoft.com/ru-ru/library/hh156528.aspx
    Выражение await не блокирует поток, в котором оно выполняется. Вместо этого оно указывает компилятору объявить оставшуюся часть асинхронного метода как продолжение ожидаемой задачи. Управление затем возвращается методу, вызвавшему асинхронный метод. Когда задача завершается, она вызывает свое продолжение и возобновляет выполнение асинхронного метода с того места, где она была прервана.

    Метод Task.Run ставит в очередь заданную задачу для запуска в пуле потоков.

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

    // без ожидания
    Console.WriteLine(DateTime.Now);
    
    Task.Run(() => { Thread.Sleep(5000); });
    
    // этот код будет выполнен сразу
    Console.WriteLine(DateTime.Now);
    
    // ожидание с await
    Console.WriteLine(DateTime.Now);
    
    await Task.Run(() => { Thread.Sleep(5000); });
    
    // этот код будет выполнен, только после завершения выполнения задачи
    // текущий (вызывающий) поток не будет приостановлен
    // (например, в Windows Form это будет хорошо видно)
    Console.WriteLine(DateTime.Now);

    Если сделать задачу и вызвать метод Wait, то основной поток будет приостановлен, пока не завершится задача.

    Console.WriteLine(DateTime.Now);
    
    var t = Task.Run(() => { Thread.Sleep(5000); });
    t.Wait(); // ожидание выполнения задачи
    
    // этот код будет выполнен, только после завершения выполнения задачи
    // текущий (вызывающий) поток будет блокирован
    // (например, в Windows Form это будет хорошо видно)
    Console.WriteLine(DateTime.Now);

    74ad1b048cee439faab48113a61a7ec7.gif
    Ответ написан
    6 комментариев
  • ASP NET Как хранить данные внутри приложения?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    У приложения есть события запуска и завершения работы.

    Общие данные можно загружать при запуске приложения (Application_Start) или подгружать в статические классы в процессе работы приложения. Либо использовать HttpApplication, хотя смысла в этом особого нет.

    Важную информацию можно сохранить при завершении работы приложения (Application_End) в любое удобное хранилище (базы данных, файлы). Если данные очень важны, то лучше их периодически сохранять в процессе работы приложения (сделать таймер при инициализации приложения), т.к. рабочий процесс может быть завершен некорректно и событие Application_End может не возникнуть. Также следует учитывать вероятность неожиданного завершения работы приложения в момент сохранения важных данных (например, если рабочий процесс будет убит).

    Временные данные можно хранить в кэше.

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

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Проще всего запомнить ссылку и не извращаться:
    // создаем переменную типа EventHandler
    EventHandler handler = null;
    // создаем анонимный метод для обработки события и передаем его переменной
    handler = (sender, e) =>
    {
      MessageBox.Show("Hello!");
      // удаляем обработчик
      ((Button)sender).Click -= handler;
    };
    // добавляем обработчик
    button1.Click += handler;

    Плохое решение может выглядеть так:
    // добавляем обработчик
    button1.Click += (sender, e) =>
    {
      MessageBox.Show("Hello!");
    
      // получаем поле EventClick
      var f = typeof(Control).GetField
      (
        "EventClick", 
        BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static
      );
    
      // получаем значение EventClick для sender
      var k = f.GetValue(sender);
    
      // получаем свойство 
      var p = sender.GetType().GetProperty
      (
        "Events", BindingFlags.NonPublic | BindingFlags.Instance
      );
    
      // получаем значение свойства Events для sender
      var events = (EventHandlerList)p.GetValue(sender, null);
    
      // удаляем обработчик из списка событий
      events.RemoveHandler(k, events[k]);
    };

    В собственных классах проще получить список делегатов при помощи GetInvocationList (внутри класса):
    public class Toster
    {
    
      public event EventHandler AnyEvent;
    
      public void AnyEventHarakiri()
      {
        foreach (Delegate d in this.AnyEvent.GetInvocationList())
        {
          this.AnyEvent -= (EventHandler)d;
        }
      }
    
    }

    var t = new Toster();
    t.AnyEvent += (sender, e) => { };
    t.AnyEventHarakiri();

    Но вариант со ссылками лучше.
    Ответ написан
    3 комментария
  • Как правильно работать с большой базой через C# + MsSQLL?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Если есть возможность, лучше удалять данные полностью, а потом добавлять новые при помощи SqlBulkCopy.

    Таким образом можно будет большие, я бы даже сказал огромные, объемы данных помещать в базу за короткий промежуток времени. Лучше всего не все сразу, а частями. Например, если 5 000 000 записей, то пачкой 10 000, или по 1 000. Зависит от объема данных и вероятности возникновения ошибок в процессе переноса. Если там простые данные, типа чисел, то можно их одним махом залить в базу. Если пачка будет слишком большой, серверу может памяти не хватить на её обработку.

    Быстро удалить данные можно при помощи инструкции TRUNCATE TABLE [имя таблицы], но не всегда просто, зависит от связей.

    Организовать обновление будет сложнее. Лучше всего выбирать пачку данных, обрабатывать и отправлять обратно на сервер. Размер пачки необходимо определять в зависимости от ресурсов сервера и объема данных в пачке.
    Запросы при обновлении должны быть максимально простыми. Можно использовать XML, но тоже очень простой и небольших объемов, а в идеале обойтись без этого. Чем все будет проще, тем быстрее будет работать. Циклы и курсоры в запросах стараться не использовать.

    Проверку наличия данных можно реализовать на стороне приложения, а не базы. Практика показывает, что это работает быстрее. Перед обновлением можно получить только идентификаторы данных (в DataTable). Далее проверять, есть необходимый идентификатор в DataTable или нет. Чтобы было проще, можно обновлять все данные, если идентификатор будет найден. А если нет, то добавлять данные. Это позволит не делать EXISTS на стороне SQL Server и обновление можно будет выполнить пачкой. Если использовать XML, то примерно так это может выглядеть:

    -- временная таблица
    -- в моем примере всего два поля id и value
    CREATE TABLE #tmp
    (
      num int primary key identity,
      id bigint,
      value nvarchar(max)
    );
    
    -- структура xml:
    -- <items>
    -- <item id="123">значение</item>
    -- <item id="456">значение</item>
    -- </items>
    
    -- переносим xml в таблицу
    INSERT INTO #tmp
    SELECT 
    ISNULL(n.value('@id', 'bigint'), 0), -- идентификатор существующих данных
    n.value('.', 'nvarchar(max)') -- значение данных
    FROM @xml.nodes('/items/item') AS node(n);
    
    -- обновляем записи в таблице [table], у которых есть идентификатор
    UPDATE a SET value = b.value
    FROM table AS a 
    INNER JOIN #tmp AS b ON a.id = b.id
    WHERE b.id <> 0;
    
    -- добавляем записи, у которых нет идентификатора
    INSERT INTO table (value)
    SELECT value FROM #tmp AS b WHERE b.id = 0;
    
    -- удаляем временную таблицу
    DROP TABLE #tmp;

    Если есть возможность, лучше обойтись без XML, JOIN-ов и всяких ISNULL.

    Базу необходимо правильно настроить. Добавить индексы, где будет уместно. Но не переборщить и учитывать, что они (индексы) могут фрагментироваться и сильно замедлять работу базы. Про фрагментацию самой базы, тоже не стоит забывать. Если будете удалять большие объемы данных, то не забывайте выполнять резервное копирование и сжатие базы.

    Соединения с базой лучше использовать одноразовые. Т.е. открыл, выполнил запрос, закрыл и так далее. Если использовать одно соединение, то со временем скорость выполнения запросов будет существенно снижаться.

    Универсального решения подобных задач нет, но это примерно то, от чего можно отталкиваться.
    Ответ написан
    9 комментариев
  • Как сделать так, чтобы после нажатия кнопки можно было щелкнуть мышкой в PictureBox и там бы нарисовался круг?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Фигуры фиксированного размера можно нарисовать так:
    public partial class Form1 : Form
    {
    
        private int BrushType = 1;
    
        public Form1()
        {
          InitializeComponent();
    
          // создаем PictureBox
          var pic = new PictureBox { Dock = DockStyle.Fill, BackColor = Color.White };
          pic.MouseClick += PictureBox_MouseClick;
          this.Controls.Add(pic);
    
          // создаем панель для кнопок
          var panel = new FlowLayoutPanel { Dock = DockStyle.Top, AutoSize = true };
          this.Controls.Add(panel);
    
          // кнопки
          var btn = new RadioButton 
          { 
            Text = "Круг", 
            Tag = 1, 
            Appearance = Appearance.Button, 
            Checked = true, 
            AutoSize = true 
          };
          btn.Click += Button_Click;
          panel.Controls.Add(btn);
    
          btn = new RadioButton
          {
            Text = "Не круг",
            Tag = 2,
            Appearance = Appearance.Button,
            AutoSize = true
          };
          btn.Click += Button_Click;
          panel.Controls.Add(btn);
    
          btn = new RadioButton
          {
            Text = "Квадратный круг",
            Tag = 3,
            Appearance = Appearance.Button,
            AutoSize = true
          };
          btn.Click += Button_Click;
          panel.Controls.Add(btn);
        }
    
        private void Button_Click(object sender, EventArgs e)
        {
          var btn = (RadioButton)sender;
          this.BrushType = (int)btn.Tag;
        }
    
        private void PictureBox_MouseClick(object sender, MouseEventArgs e)
        {
          // получаем ссылку на PictureBox
          var pic = (PictureBox)sender;
          // получаем Graphics из PictureBox
          var g = pic.CreateGraphics();
    
          if (this.BrushType == 2)
          {
            // рисуем не круглый квадрат
            g.DrawRectangle(Pens.Black, e.X, e.Y, 50, 50);
          }
          else if (this.BrushType == 3)
          {
            // рисуем квадратный круг
            Point[] points = new Point[6];
            int half = 50 / 2;
            int quart = 50 / 4;
            points[0] = new Point(e.X + quart, e.Y);
            points[1] = new Point(e.X + 50 - quart, e.Y);
            points[2] = new Point(e.X + 50, e.Y + half);
            points[3] = new Point(e.X + 50 - quart, e.Y + 50);
            points[4] = new Point(e.X + quart, e.Y + 50);
            points[5] = new Point(e.X, e.Y + half);
            g.DrawPolygon(Pens.Black, points);
          }
          else
          {
            // рисуем эллипс
            g.DrawEllipse(Pens.Black, e.X, e.Y, 50, 50);
          }
        }
    
    }

    В качестве кнопок используются RadioButton, т.к. это удобней.
    Чтобы не стиралось, можно сделать Bitmap:
    var pic = (PictureBox)sender;
    if (pic.Image == null) { pic.Image = new Bitmap(pic.Width, pic.Height); }
    var bmp = new Bitmap(pic.Image);
    var g = Graphics.FromImage(bmp);

    И после завершения рисования, передать картинку в PictureBox:
    pic.Image = bmp;

    Результат:
    c141d6f9ebe44712a5d9c5f9aa67dcb1.png
    Ответ написан
    1 комментарий
  • Как повысть скорость записи случайных блоков?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Можно попробовать использовать MemoryMappedFile:
    string path = @"1.dat";
    int len = 1024 * 1024;
    
    var rnd = new Random();
    var sw = Stopwatch.StartNew();
    
    var b = new byte[4];
    
    Console.WriteLine("Test started");
    
    using (var map = MemoryMappedFile.CreateFromFile(path, FileMode.Create, path, len))
    {
      using (var accessor = map.CreateViewAccessor())
      {
        for (var i = 0; i < len / 4; ++i)
        {
          b[0] = (byte)rnd.Next(0, 255);
          b[1] = (byte)rnd.Next(0, 255);
          b[2] = (byte)rnd.Next(0, 255);
          b[3] = (byte)rnd.Next(0, 255);
    
          accessor.WriteArray(rnd.Next(0, len / 4) * 4, b, 0, 4);
        }
      }
    }
          
    Console.WriteLine("Test end time - " + sw.ElapsedMilliseconds);
    Console.ReadKey();
    Ответ написан
  • Какие требования у.NET при стандартной сериализации?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Чтобы класс можно было сериализовать, необходимо пометить его атрибутом [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, как это работает.
    Ответ написан
    Комментировать
  • Разве StringWriter унаследован от Stream?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Метод Serialize перегружен и, помимо прочего, может принимать TextWriter, от которого наследуется StringWriter.
    Ответ написан
    Комментировать
  • Что за страности в Stream в.NET?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    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.
    Ответ написан
    3 комментария
  • Как бы вы реализовали фильтрацию по нескольким полям в Entity Framework?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Для поиска по массиву - Array.IndexOf. Будет работать в LINQ наверняка не скажу, сам бы так поступать с данными из базы не стал. SQL - наше все :)
    string[] arr = {"слово 1", "слово 2"};
    return DbSet.Where(u => Array.IndexOf(arr, u.FirstName) != -1);


    Еще вариант, более плохой, но с возможность игнорировать регистр:
    string[] arr = {"слово 1", "слово 2"};
    return DbSet.Where(u => arr.Any(itm=> itm == u.FirstName));
    Ответ написан
    Комментировать
  • Существует электронный справочник по.NET?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    В MSDN поиск не удобный, но с этой задачей неплохо справляется Google.

    Локальное средство просмотра Microsoft Help, по сути, будет тоже самое, с тем лишь отличием, что информация может храниться локально.

    Свежее данных, чем в MSDN, в любом случае не найти.
    Формат документации за последнее время стал заметно лучше и понятней. Вот раньше было совсем все плохо :)
    Ответ написан
    Комментировать