Ответы пользователя по тегу C#
  • Чем отличается Visual C# от C#?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Под C# обычно следует понимать Visual C#, точнее Microsoft Visual C#.

    Microsoft Visual C# - реализация языка C# компанией Microsoft.

    Наверное выглядит странно, учитывая что язык создан в Microsoft для Microsoft .NET Framework, но на данный момент есть две спецификации C#: ECMA-334, ISO/IEC 23270:2006 (в чем разница, не имею представления).
    Microsoft штампует новые версии C# со страшной скоростью, и как следствие выпускает новые спецификации :-)

    Из-за разных реализация C#, стандартов, юридических проблем в языке появляются искажения и не стыковки. Например, при программировании под Mono есть мелкие особенности, которые следует учитывать. А в целом, C# - он один.
    Ответ написан
  • Часто ли вы используете интерфейсы?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Интерфейсы использую, если это необходимо :-) Как я понимаю, что это необходимо, сказать сложно. Все зависит от задачи. Если рассматривать вопрос с позиции создания интерфейсов, то иногда это может быть очевидно, а иногда приходится подумать, стоит использовать интерфейсы или нет. Пихать их где попало - плохая идея.

    Готовые интерфейсы, да, часто используются. Самым популярным в .NET наверное будет IDisposable :-)

    Из общедоступных практических примеров использования собственных интерфейсов:

    • Простой интерфейс, описывающий всего один метод.

      interface ILoginForm
      {
      
        void WebDocumentLoaded(System.Windows.Forms.WebBrowser webBrowser, Uri url);
      
      }


      В проекте 100500 форм. Для некоторых форм может потребоваться индивидуальная обработка результатов, как здесь. А для других - нет. Все формы наследуются от базового класса, в котором я могу проверить, реализует текущий экземпляр интерфейс с индивидуальным обработчиком результатов или нет, и вызвать его.

      if (typeof(ILoginForm).IsAssignableFrom(this.GetType()))
      {
        this.CanLogin = false;
        Debug.WriteLine("ILoginForm", "LoginForm");
        ((ILoginForm)this).WebDocumentLoaded(this.webBrowser1, e.Url);
      }


    • Вот другой пример интерфейса.

      export interface ILocalization {
      
        Loading: string;
      
        LoadingFileContents: string;
      
        // ...
      }

      Файлы с ресурсами локализации реализуют этот интерфейс.

      export class RU implements ILocalization {
      
        public Loading: string = 'Загрузка...';
      
        public LoadingFileContents: string = 'Получение содержимого файла...';
      
        // ...
      }

      Это просто упрощает работу с кодом и больше ничего.

      6d84933efd7246e6adbeeed114ef8bbe.png

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


    • Еще пример интерфейса для вспомогательных классов работы с базами данных. Он просто описывает, каким должен быть класс.

      interface IDBClient
      {
          
        public function ExecuteNonQuery();
        public function ExecuteScalar();
        public function GetRow();
        // ...
      
      }

      А толку от этого никакого.

      Интерфейсы для слоев взаимодействия с БД я делаю частенько, с замахом на замену СУБД, но сделать это красиво в любом случае не получится, все равно придется вносить корректировки при изменении источника данных, так что практической пользы от таких интерфейсов мало, но иногда она есть, только для других целей.

    • А вот тут я реализовал множество готовых интерфейсов, чтобы получить нужные свойства и поведение класса. Например, интерфейс IConvertible позволяет адекватно реагировать на Convert.To*. Интерфейс ISerializable позволяет описать правила сериализации экземпляра класса. И т.п.

      // реализация метода ToInt32
      public int ToInt32(IFormatProvider provider)
      {
        // если пусто, возвращаем ноль
        if (!this.HasValue) { return 0; }
        // если что-то есть, извлекаем числа и пробуем вернуть int32
        return Convert.ToInt32(OAuthUtility.GetNumber(this.Data));
      }


    • Вот пример, где можно было использовать интерфейсы, но я принял решение в пользу базовых классов (на раннем этапе). Некоторые поставщики OAuth позволяют обновлять маркер доступа и/или отзывать его, но не все. В базовом классе нижнего уровня для определениях этих особенностей я сделал два свойства, причем даже не абстрактных.

      public bool SupportRevokeToken { get; protected set; }
      public bool SupportRefreshToken { get; protected set; }

      Клиенты, которым нужны эти свойства, задают их в конструкторе, выглядит это так.

      public GoogleClient(string clientId, string clientSecret) : base(/*...*/)
      {
        // ...
        base.SupportRevokeToken = true;
        base.SupportRefreshToken = true;
      }

      Не очень красиво, но ошибкой это назвать нельзя. Если бы я использовал интерфейсы, то для отзыва и обновления маркера мне бы пришлось делать два разных интерфейса, в каждом по одному bool свойству, либо пустых (но с явно определенным свойством для других программистов все было бы очевидней; это тоже спорный вопрос). Можно было пойти дальше и измельчить на интерфейсы другие особенности, но это было бы плохим решением, т.к. программистам пришлось бы указывать портянку интерфейсов, а потом писать много кода. С базовыми классами код писать не нужно, даже не нужно вникать в то, как это работает; в большинстве случаев достаточно просто выполнить простую конфигурацию дочернего класса в конструкторе. Но я не могу утверждать на 100%, что это лучшее решение для данного случая.

    • Пример, где ReactJS и TypeScript заставляют клепать интерфейсы и я этому совсем не рад.

      export interface ILoginState {
      
        Username?: string;
        Password?: string;
      
        // ...
      
      }
      
      export default class Index extends Page<any, ILoginState> {
      
        constructor() {
      
          this.state = {
            Username: '',
            Password: ''
          };
      
        }
      
        // ...
      
      }

      Можно забить и использовать анонимные типы, но для порядка и удобства работы с кодом придется открывать собственный завод по производству интерфейсов :-)

    Ответ написан
    Комментировать
  • Не могу вернуть значение C#. В чем ошибка?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Параметр в метод не передан:
    int h = obj.Met(--> ???? <--);
    Вызываем метод Met, в первом параметре указываем значение 123, результат передаем в переменную h:
    int h = obj.Met(123);
    Console.WriteLine("Получен результат: {0}", h);
    Ответ написан
    1 комментарий
  • Как в RichTextBox игнорировать/блокировать режим "замена" через insert?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Добавить к экземпляру richTextBox обработчик события KeyDown и отменить нажатие Insert:
    private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
    {
      if (e.KeyCode == Keys.Insert)
      {
        e.Handled = true;
        return;
      }
    }
    Ответ написан
  • С# уменьшение кода?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    label.Content = (Convert.ToInt32(textBox.Text) + Convert.ToInt32(textBox1.Text)).ToString();

    Или функцию написать и использовать её:
    private static string Sum(string a, string b)
    {
      return (Convert.ToInt32(a) + Convert.ToInt32(b)).ToString();
    }

    Или даже так:
    label.Content = Sum(textBox.Text, textBox1.Text);
    label.Content = Sum(textBox.Text, textBox1.Text, textBox2.Text, textBox4.Text);
    
    private static string Sum(params string[] n)
    {
      return n.Sum(itm => Convert.ToInt32(itm)).ToString();
    }


    Еще можно расширение написать, но это только на случай, если сложение чисел в TextBox являются частыми в проекте :-)
    public static class TextBoxExtension
    {
    
      public static string SumWith(this TextBox value, params TextBox[] n)
      {
        return (Convert.ToInt32(value.Text) + n.Sum(itm => Convert.ToInt32(itm.Text))).ToString();
      }
    
    }

    label.Content = textBox.SumWith(textBox1, textBox2, textBox3);

    Либо расширить string:
    public static class StringExtension
    {
    
      public static string SumWith(this string value, params string [] n)
      {
        return (Convert.ToInt32(value) + n.Sum(itm => Convert.ToInt32(itm))).ToString();
      }
    
    }

    label.Content = textBox.Text.SumWith(textBox1.Text);
    Ответ написан
    Комментировать
  • Как в родительской форме перехватить закрытие дочерней?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Просто обработчик события закрытия формы добавить:
    var f = new Form2();
    f.Owner = this;
    
    f.FormClosed += (object s, FormClosedEventArgs args) =>
    {
      MessageBox.Show("Форма закрыта!");
    };
    
    f.Show();

    Либо так:
    private void button1_Click(object sender, EventArgs e)
    {
      var f = new Form2();
      f.Owner = this;
    
      f.FormClosed += Form2_FormClosed;
    
      f.Show();
    }
    
    private void Form2_FormClosed(object sender, FormClosedEventArgs e)
    {
      MessageBox.Show("Форма закрыта!");
    }

    Еще можно показать дочернюю форму как диалог (для контейнера Mdi не подойдет):
    var f = new Form2();
    f.Owner = this;
    // главная форма будет недоступна
    f.ShowDialog();
    // после закрытия диалоговой формы, выполнение продолжится
    MessageBox.Show("Форма закрыта!");
    Ответ написан
    Комментировать
  • Как вызвать хранимую процедуру из приложения?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    dataAdapter = new SqlDataAdapter("Имя процедуры", connectionString);
    dataAdapter.SelectCommand.CommandType = CommandType.StoredProcedure;

    Либо с использованием SqlCommand:
    var connection = new SqlConnection(connectionString);
    // connection.Open();
    var cmd = new SqlCommand("Имя процедуры", connection);
    cmd.CommandType = CommandType.StoredProcedure;
    dataAdapter = new SqlDataAdapter(cmd);
    Ответ написан
    Комментировать
  • Как переписать данный алгоритм на C#?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Подводя итоги обсуждения в комментариях.

    bytearray - не содержит текст. Это тело файла Flash.

    В строке:
    s = s + (base64[i + 1] + base64[i]);

    Следует работать с символами как со строками, а не кодами символов:
    s = s + (base64[i + 1].ToString() + base64[i].ToString());


    В остальном вроде ошибок нет. Код использования примерно такой:
    byte[] data;
    data = Convert.FromBase64String(DecryptBFF(book.Content));
    File.WriteAllBytes("output.swf", data);

    Файл output.swf можно открыть в проигрывателе Flash или браузере.

    Будем надеяться, что все законно :-)
    Ответ написан
    1 комментарий
  • Как восстановить в окне конструктора случайно удаленный контрол в winforms?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    С Windows Forms нужно быть готовым к разного рода фокусам со стороны Visual Studio.
    Даже при использовании систем контроля версий, порой приходится повозиться с подлянками в виде пропавших картинок или дочерних элементов в каком-нибудь меню или ToolStrip. Многие подобные случаи можно поправить руками, путем ручного исправления файлов Designer, но не всегда. Чем сложнее форма, тем выше риск того, что дизайнер студии что-нибудь сломает; всегда нужно быть к этому готовым.

    1. Раз появился такой вопрос, то видимо Ctrl + Z точно уже не поможет. Это первое, что нужно было сделать.

    2. Если форма не была сохранения, то для отката изменений можно было бы её просто закрыть без сохранения. Но опять же, это нужно было делать сразу, при возникновении проблемы и если обычный откат назад (Ctrl + Z) не помог.

    3. Если не используется система контроля версий, то нужно регулярно делать резервные копии исходного кода. Использование системам контроля версий будет удобней. Но даже при использовании систем контроля версий, следует регулярно делать резервные копии, и резервные копии резервных копий.

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

    Описание элементов формы, по умолчанию, находятся в файлах Designer. Например, элементы Form1 можно найти в файле Form1.Designer.cs. Иногда у элементов могут просто потеряться ссылки на родителей. Случай случайного удаления элемента и отката назад (Ctrl + Z) как раз-таки может привести к подобному поведению. Код в файле Designer обычно остается и ссылки можно поправить руками. Как правило, речь идет о добавлении строчек кода вида: this.родительскийЭлемент.Controls.Add(this.дочернийЭлемент). Главное понимать, что от чего отвалилось и что к чему нужно привязать. Если не понимать, то можно сделать хуже :-) (не стоит забывать про создание резервных копий). После внесения изменений в код дизайнера, следует переоткрыть конструктор форм (в идеале, перед внесением изменений в *.Designer.cs, конструктор форм (визуальный редактор форм) лучше закрыть).

    Если элемент удален полностью и использовать восстановление из предыдущей сборки, то в декомпилированном коде нужно будет найти класс формы, а в нем метод InitializeComponent. У DataGridView, каждая колонка и строка (при наличии) будут являться отдельными элементами, нужно найти и перенести весь код описания этих элементов. Как правило, для каждого отдельного элемента, установка значений свойствам в коде идет последовательно. Дочерние элементы могут идти в разброс, по именам элементов можно более ли менее понять, что к чему (если стандартные имена у элементов менялись на собственные, то проблем с поиском возникнуть не должно).
    Ответ написан
    Комментировать
  • C# checkbox .Checked xaml?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Checked - это событие.

    Состояние можно задать свойством IsChecked:
    CheckBox cb = (CheckBox)sender;
    cb.IsChecked = true;
    Ответ написан
    1 комментарий
  • Как отписаться от события, если в качестве подписки лямбда выражение?

    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# После загрузки картинки в picturebox удалить её с диска?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Работать с файлами лучше через FileStream, чтобы полностью контролировать весь процесс:
    string filePath = "123.jpg";
    
    using (var file = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Inheritable))
    {
      pictureBox1.Image = Image.FromStream(file);
    }
    
    File.Delete(filePath);

    Многие упрощенные методы работы с файлами нередко блокируют доступ к файлам. Такие методы имеет смысл использовать только для одноразовых файловых операций (когда нужно один раз прочитать или записать данные и не более этого).
    Ответ написан
    Комментировать
  • В чём польза readonly полей в C#?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Значения полей 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));
        }
        
      }
    
    }
    Ответ написан
    Комментировать
  • Как повторить структуру treeview в menu?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Рекурсия:
    private void button1_Click(object sender, EventArgs e)
    {
      // создаем меню
      var menu = new MenuStrip();
      menu.Items.Add("Меню");
    
      // перебираем узлы
      foreach (TreeNode n in treeView1.Nodes)
      {
        // создаем элемент меню
        var menuItem = new ToolStripMenuItem();
        menuItem.Text = n.Text;
        // перебирем детей
        ConvertNodeToMenu(menuItem, n);
        // добавляем элемент в меню
        ((ToolStripMenuItem)menu.Items[0]).DropDownItems.Add(menuItem);
      }
          
      // добавляем меню на форму
      this.Controls.Add(menu);
    }
    
    private void ConvertNodeToMenu(ToolStripMenuItem menuParent, TreeNode node)
    {
      foreach (TreeNode n in node.Nodes)
      {
        // создаем элемент меню
        var menuItem = new ToolStripMenuItem();
        menuItem.Text = n.Text;
        // перебираем детей
        ConvertNodeToMenu(menuItem, n);
        // добавляем элемент в меню
        menuParent.DropDownItems.Add(menuItem);
      }
    }

    Вариант с LINQ:
    private void button1_Click(object sender, EventArgs e)
    {
      // создаем меню
      var menu = new MenuStrip();
      menu.Items.Add("Меню");
      // берем первый элемент меню
      var menuItem = (ToolStripMenuItem)menu.Items[0];
      // получаем узлы и добавляем в меню
      menuItem.DropDownItems.AddRange
      (
        treeView1.Nodes.Cast<TreeNode>().Select
        (
          n => new ToolStripMenuItem(n.Text, null, ConvertNodeToMenu(n))
        ).ToArray()
      );
      // добавляем меню на форму
      this.Controls.Add(menu);
    }
    
    private ToolStripMenuItem[] ConvertNodeToMenu(TreeNode node)
    {
      return node.Nodes.Cast<TreeNode>().Select
      (
        n => new ToolStripMenuItem(n.Text, null, ConvertNodeToMenu(n))
      ).ToArray();
    }
    Ответ написан
    6 комментариев
  • Возможна ли авторизация OAuth 2.0 без браузера?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Поставщик может позволить принимать у пользователя логин и пароль и преобразовывать их в маркер доступа (accsss token). Но, как правило в целях безопасности, никто не дает такой возможности.

    Попробуйте: если grant_type будет password, то данные пользователя можно передавать в параметрах username и password при получении маркера доступа. Либо использовать grant_type равный client_credentials, тогда данные пользователя должны передаваться в HTTP заголовке Authorization (при использовании HTTPS это более безопасный способ, чем password).

    Например, если бы Facebook позволял это делать, то запрос маркера доступа мог бы быть таким:
    https://graph.facebook.com/oauth/access_token?client_id=123&client_secret=abc&
    grant_type=password&username=pupkin&password=000


    В моей библиотеке пока нет возможности менять grant_type снаружи, но можно внутри поменять. Например, InstagramClient.cs, в конструкторе указать GrantType:

    base.GrantType = GrantType.ClientCredentials;

    И далее использовать клиент:

    var client = new InstagramClient
    (
      "9fcad1f7740b4b66ba9a0357eb9b7dda", 
      "3f04cbf48f194739a10d4911c93dcece"
    );
    client.ReturnUrl = "http://oauthproxy.nemiro.net/";
    client.Username = "aleksey";
    client.Password = "Frif#dser#23dssd@Dsdfjjfsi";
    var accessToken = client.AccessToken;

    И сервер ответит:
    {"code": 400, "error_type": "OAuthException", "error_message": "Invalid grant_type"}

    Плохой пример :P

    А вот Facebook, на удивление, вернул маркер доступа:
    var client = new FacebookClient("1435890426686808", "c6057dfae399beee9e8dc46a4182e8fd");
    client.Username = "aleksey";
    client.Password = "a6lGmDZsCb1SuHsIQw89ZqK9";
    var accessToken = client.AccessToken;

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

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    
    namespace WindowsFormsApplication9
    {
      public partial class Form1 : Form
      {
    
        /// <summary>
        /// Получает текущее положение ползунка полосы прокрутки.
        /// </summary>
        /// <param name="hWnd">Дескриптор.</param>
        /// <param name="nBar">Тип.</param>
        /// <returns></returns>
        [DllImport("User32.dll")]
        public extern static int GetScrollPos(IntPtr hWnd, int nBar);
    
        /// <summary>
        /// Функция для отправки сообщений.
        /// </summary>
        /// <param name="hWnd">Дескриптор.</param>
        /// <param name="msg">Само сообщение.</param>
        /// <param name="wParam">Параметры.</param>
        /// <param name="lParam">Дополнительные параметры.</param>
        [DllImport("User32.dll")]
        public extern static int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
    
        public enum ScrollBarType : uint
        {
          SbHorz = 0,
          SbVert = 1,
          SbCtl = 2,
          SbBoth = 3
        }
    
        public enum Message : uint
        {
          /// <summary>
          /// Сообщение для вертикальной полосы прокрутки
          /// </summary>
          WM_VSCROLL = 0x0115
        }
    
        public enum ScrollBarCommands : uint
        {
          /// <summary>
          /// Положение ползунка полосы прокрутки в конце операции
          /// </summary>
          SB_THUMBPOSITION = 4
        }
    
        private RichTextBox rich1 = new RichTextBox();
        private RichTextBox rich2 = new RichTextBox();
    
    
        public Form1()
        {
          InitializeComponent();
    
          // тестовый текст
          string text = "";
          for (int i = 0; i < 99; i++)
          {
            text += "Имеется 2 richTextBox, нужно установить значение текущего вертикального скролла первого, как у в данный момент у второго. Пробовал всякие offset, копался в гугле, но ничего внятного не нашел.\r\n";
          }
    
          // добавляем поля на форму
          rich1.Name = "rich1";
          rich1.Dock = DockStyle.Top;
          rich1.Text = text;
          rich1.VScroll += rich_VScroll;
          this.Controls.Add(rich1);
    
          rich2.Name = "rich2";
          rich2.Dock = DockStyle.Top;
          rich2.Text = text;
          rich2.VScroll += rich_VScroll;
          this.Controls.Add(rich2);
        }
    
        /// <summary>
        /// Обработчик изменения положения ползунка полосы прокрутки.
        /// </summary>
        private void rich_VScroll(object sender, EventArgs e)
        {
          // кто вызвал событие
          RichTextBox currentRich = (RichTextBox)sender;
          // если событие вызвал rich2, то второй будет rich1 и наоборот
          RichTextBox otherRich = currentRich.Name.Equals("rich1") ? rich2 : rich1;
    
          // получаем позицию ползунка полосы прокрутки текущего поля
          int pos = GetScrollPos(currentRich.Handle, (int)ScrollBarType.SbVert);
          pos <<= 16;
    
          // чтобы не застрять в бесконечности 
          // (можно так не делать и прикрутить обработчик только к одному полю)
          otherRich.VScroll -= rich_VScroll; 
          // --
    
          // передаем позицию во второе поле
          uint par = (uint)ScrollBarCommands.SB_THUMBPOSITION | (uint)pos;
          SendMessage(otherRich.Handle, (int)Message.WM_VSCROLL, new IntPtr(par), new IntPtr(0));
          otherRich.VScroll += rich_VScroll;
        }
      }
    }
    Ответ написан
    2 комментария
  • Приложение не запускается на WinXP, как можно исправить?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    На Windows XP должен быть установлен .NET Framework. В данном случае, версия 2.0. Также может потребоваться Service Pack 3.

    Лучше ниже .NET Framework 3.5 не использовать.
    И .NET Framework 4.0 под Windows XP вполне нормально работает, если установить. Версия 4.5 уже не поддерживается

    .NET 2.0, если не изменяет память, по умолчанию не входил в состав Windows XP (если хотелось именно этого).
    Ответ написан
    2 комментария
  • Как заставить Newtonsoft.Json вернуть чистый json?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Newtonsoft.Json тут не причем. Дело в запросе, со стороны клиента. Нужно указать тип содержимого application/json и передать JSON в data:
    $.ajax({
    	type: "POST",
    	url: "WebService1.asmx/VerifySignature",
    	contentType: "application/json",
    	data: JSON.stringify({ certInfo: keyInfo }), // обернуть все параметры
    	success: function (result) {
    		alert(result);
    		console.log(result);
    	}
    });
    Ответ написан
    2 комментария
  • Сортировка элементов строки?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Можно разбить на массив по пробелу и выполнить сортировку массива, затем обратно склеить:
    var value = "a ack fghjy fghfh asn";
    // разбиваем на массив
    var arr = value.Split();
    // сортируем массив
    Array.Sort(arr);
    // склеиваем массив в строку
    string result = String.Join(" ", arr);
    // выводим результат
    Console.WriteLine(result);

    Или при помощи OrderBy:
    Console.WriteLine(String.Join(" ", "a ack fghjy fghfh asn".Split().OrderBy(itm=>itm)));

    Первый вариант оптимальней.
    Посмотреть пример.
    Ответ написан
    5 комментариев
  • Как правильно работать с большой базой через 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 комментариев