воскресенье, 21 ноября 2010 г.

Давай я за тебя погуглю!

Lass mich das für dich GOOGLEn!

http://lmgtfy.com/
Эта страничка посвящается всем тем, кто не желает самостоятельно воспользоваться поисковиком, а достает всех своими вопросами.

Пользоваться примерно так:
http://lmgtfy.com/?q=как+правильно+искать+информацию

воскресенье, 24 октября 2010 г.

Perfomance Counter. Счетчик производительности

Когда мы хотим измерить производительность кода, нас интересует время, потраченое на его выполнение. Для этого можно "запомнить" время ДО, и время ПОСЛЕ, вычислить разницу и анализировать результат. В этом случае считается, что процессор все время будет выполнять только этот код. Но на практике может получится так, что во время выполения поток дойдет до середины, процессор переключится на другие потоки, обойдет их, и через некоторое время вернется к нашему. Естественно измерения в этом случае некорректны.

С учетом вышеизложенного, для точных расчетов я использую следующий класс (сперто где-то с просторов интернета):

  class PerfCounter
  {
    private static TimeSpan spStartKernelTime;
    private static TimeSpan spStartUserTime;
    private static ProcessThread procThread;
    private static Int32 idCurrentThread;

    [DllImport("kernel32.Dll", SetLastError = true)]
    public static extern UInt32 GetCurrentThreadId();
    public static bool StartCountOnThread()
    {
      idCurrentThread = (Int32)GetCurrentThreadId();
      try
      {
        foreach (ProcessThread prThread in Process.GetCurrentProcess().Threads)
        {
          if (prThread.Id == idCurrentThread)
          {
            procThread = prThread;
            spStartKernelTime = prThread.TotalProcessorTime;
            spStartUserTime = prThread.UserProcessorTime;
            return true;
          }
        }
      }
      catch (System.Exception e)
      {
        System.Console.WriteLine(e.Message);
        //System.Windows.Forms.MessageBox.Show(e.Message);
        return false;
      }
      return false;
    }

    public static TimeSpan FinishCountOnThread()
    {
      try
      {
        foreach (ProcessThread prThread in Process.GetCurrentProcess().Threads)
        {
          if (prThread.Id == idCurrentThread)
          {
            return prThread.TotalProcessorTime +
             prThread.UserProcessorTime -
             spStartKernelTime - spStartUserTime;
          }
        }
      }
      catch (System.Exception e)
      {
        //System.Windows.Forms.MessageBox.Show(e.Message);
        System.Console.WriteLine(e.Message);
        return TimeSpan.Zero;
      }
      return TimeSpan.Zero; ;

    }
  }


* This source code was highlighted with Source Code Highlighter.

воскресенье, 17 октября 2010 г.

Ранкинг (Ranking). SQL запросы с рангом (Rank).

Ранкинг (Ranking) - это предоставление информации о соответствии найденной записи определенному запросу. Это соответствие в простейшем случае можно отобразить в процентном соостветсвии. Т.е. записи удовлетворяющие всем критериям имеют 100%-ный ранкинг.

Реализация ранкинга может показаться достаточно сложной задачей. Но это только так кажется. SQL может взять эту задачу на себя! Для примера я использовал MySQL, реально использовал MSSQL.

Итак, таблица:
CREATE TABLE `test_db`.`person` (
`id` INT NOT NULL,
`name` VARCHAR (100),
`age` int ,
PRIMARY KEY (`id`)
)

Наполним данными:
INSERT INTO test_db.person VALUES (1,'Ralf', 20),(2,'Peter', 30),(3,'Patrick', 40);

Найдем записи, которые соответсвуют одному из трех критериев:
- все старше 25;
- все младше 35;
- имена начинаются на "P";

Запрос может выглядеть так:
SELECT p.id, p.name, p.age FROM test_db.person p
WHERE age > 25 OR age < 35 OR name Like 'P%'


А результат запроса, так:
id, name, age
------------
1,'Ralf', 20
2,'Peter', 30
3,'Patrick',40

Добавим ранкинг (ranking). Объяснять не буду, все очень просто:
SELECT p.id, p.name, p.age, (100/3)*under1.hit + (100/3)*under2.hit + (100/3)*under3.hit AS rank FROM test_db.person p
LEFT JOIN (Select id, 1 As hit from test_db.person WHERE age > 25) AS under1 On under1.id = p.id
LEFT JOIN (Select id, 1 As hit from test_db.person WHERE age < 35) AS under2 On under2.id = p.id LEFT JOIN (Select id, 1 As hit from test_db.person WHERE name like 'p%') AS under3 On under3.id = p.id WHERE age > 25 OR age < 35 OR name like 'p%'


Результат:
id, name, age, rank
------------
1,'Ralf', 20, null
2,'Peter', 30, null
3,'Patrick', 40, null

Почти то, что нужно, но есть проблема с приведением арфиметического результа к null:
Для этого в MySql можно использовать функцию IFNULL (в MSSQL это функция ISNULL):
SELECT p.id, p.name, p.age, (100/3)*IFNULL(under1.hit, 0) + (100/3)*IFNULL(under2.hit,0) + (100/3)*IFNULL(under3.hit,0) AS rank FROM test_db.person p
LEFT JOIN (Select id, 1 As hit from test_db.person WHERE age > 25) AS under1 On under1.id = p.id
LEFT JOIN (Select id, 1 As hit from test_db.person WHERE age < 35) AS under2 On under2.id = p.id LEFT JOIN (Select id, 1 As hit from test_db.person WHERE name like 'p%') AS under3 On under3.id = p.id WHERE age > 25 OR age < 35 OR name like 'p%'


Результат:
id, name, age, rank
------------
1,'Ralf', 20, 33.333
2,'Peter', 30, 100.000
3,'Patrick', 40, 66.666

суббота, 16 октября 2010 г.

Запуск дополнительного X-Server.

Обычно Linux десктоп дистрибутив запускает одну инстанцию X-Server, которая работает в "7"-ом терминале (Alt+Ctrl+F7). Эта инстанция работает с первым X-дисплеем (X-Display). Чтобы запустить программу в другой инстанции нужно:
  • выбрать нужный терминал (Alt+Ctrl+Fx)
  • войти в терминал под своим именем паролем
  • $ xinit _prg_ -- :1 (здесь :1 - номер следующего свободного X-дисплея, нумерация с нуля)

Примеры:
$ xinit gedit -- :1
$ xinit nexuiz -- :1

Замечания:
  • Так можно запускать игры или "проблемные" программки, которые приводят с сбою графического сервера;
  • Окна программ не имеют атрибутов вашего рабочего окружения (GNOME, KDE);
  • Закрытие зависших программ - Ctrl+C
  • Информация должна быть действительна во многих Linux-дистрибутивах, проверено на Ubuntu 10.10 (64bit)

среда, 6 октября 2010 г.

XDocument. Работа с элементами без явного указания пространства имен по умолчанию (Default Namespace)

Если вы используете XDocument, Xml которого содержит явное пространство имен по умолчанию, то во время разбора элементов придется его явно указывать. Для ясности кусочки кода:
<Data xmlns="http://selo-blog.blogspot.com/">
 <Name>Иван</Name>
 <Gender>мужской</Gender>
</Data>

Чтобы получить значение тега "Name", придется выполнить следующий код:
XDocument xDoc = XDocument.Parse(inputString);
XNamespace xSpace = "http://selo-blog.blogspot.com/";
String name = xDoc.Root.Element(xSpace + "Name").Value;

Немного раздражительно, не правда ли?

Для облегчения страданий я создал следующие методы-расширения
public static class Extensions {
  public static XElement xElement(this XElement xParent, String name) {
    return xParent.Element(xParent.Name.Namespace + name);
  }

  public static IEnumerable<XElement> xElements(this XElement xParent, String name) {
    return xParent.Elements(xParent.Name.Namespace + name);
  }
}

Теперь работа с документом происходит обычным способом:
String name = xDoc.Root.xElement("Name").Value;

* This source code was highlighted with Source Code Highlighter.

понедельник, 20 сентября 2010 г.

WinForms. Простой доступ к контексту приложения.

Что бы обеспечить простой досуп к контексту приложения (ApplicationContext) я использовал слудующий подход:

public class AppContext : ApplicationContext
{
  public static AppContext Current { get; private set; }

  public AppContext() {
    if (Current == null)
      Current = this;

    this.init();
  }

  public AppContext(Form mainForm) : this() {
    this.MainForm = mainForm;
  }

  private void init() {
    // ...
  }

  int i = 0;
  public int I { get { return i++; } }
}


* This source code was highlighted with Source Code Highlighter.

Ну и теперь, собственно, в любом месте приложения:
MessageBox.Show(AppContext.Current.I + "");

понедельник, 5 июля 2010 г.

MS SQL. Замена NULL на другие значения

Встретился с небольшой проблемкой, когда в математическом выражении один из операндов является NULL, то результат выражения становится нуль. Вот нашел на просторах интернета по этому поводу следующую информацию. А мне нужно было интерпретировать NULL в 0. Для этого, к счастью, есть в MS SQL функция:
ISNULL ( check_expression , replacement_value )

Например:
SELECT Description, DiscountPct, MinQty, ISNULL(MaxQty, 0.00) AS 'Max Quantity'
FROM Sales.SpecialOffer;

среда, 19 мая 2010 г.

Стандартные операторы запросов LINQ. Справочник

Эту информацию я скомуниздил здесь.

Агрегатные функции

Aggregate
Применяет к последовательности пользовательский метод.

Average
Вычисляет среднее для числовой последовательности.

Count
Возвращает количество элементов в последовательности (целочисленное значение).

LongCount
Возвращает количество элементов в последовательности (значение в диапазоне LongInt).

Min
Возвращает наименьшее значение для числовой последовательности.

Max
Возвращает наибольшее значение для числовой последовательности.

Sum
Складывает члены числовой последовательности.

Конкатенация

Concat
Соединяет две последовательности в одну.

Преобразование

Cast
Преобразует элементы последовательности в элемены указанного типа.

OfType
Выбирает из элементов последовательности элемены указанного типа.

ToArray
Возвращает массив из элементов последовательности.

ToDictionary
Возвращает словарь из элементов последовательности.

ToList
Возвращает список из элементов последовательности.

ToLookup
Возвращает результаты поиска по последовательности.

ToSequence
Возвращает последовательность IEnumerable.

Элемент

DefaultIfEmpty
Создает стандартный элемент для пустой последовательности.

ElementAt
Возвращает элемент последовательности по указанному индексу.

ElementAtOrDefault
Возвращает элемент по указанному индексу или стандартный элемент (если индекс вышел за пределы диапазона).

First
Возвращает первый элемент последовательности.

FirstOrDefault
Возвращает первый элемент последовательности или стандартный элемент (если нужный элемент не найден).

Last
Возвращает последний элемент последовательности.

LastOrDefault
Возвращает последний элемент последовательности или стандартный элемент (если нужный элемент не найден).

Single
Возвращает единственный элемент последовательности.

SingleOrDefault
Возвращает единственный элемент последовательности или стандартный элемент (если нужный элемент не найден).

Равенство

SequenceEqual
Проверяет эквивалентность двух последовательностей.

Создание

Empty
Создает пустую последовательность.

Range
Создает последовательность в соответствии с заданным диапазоном.

Repeat
Создает последовательность, повторяя значение заданное количество раз.

Группировка

GroupBy
Группирует элементы последовательности указанным образом.

Присоединение

GroupJoin
Выполняет группированное соединение двух последовательностей.

Join
Выполняет внутреннее соединение двух последовательностей.

Упорядочение

OrderBy
Упорядочивает элементы последовательности по заданным значениям в порядке возрастания.

OrderByDescending
Упорядочивает элементы последовательности по заданным значениям в порядке убывания.

ThenBy
Упорядочивает элементы уже упорядоченной последовательности в порядке возрастания.

ThenByDescending
Упорядочивает элементы уже упорядоченной последовательности в порядке убывания.

Reverse
Зеркально отображает порядок расположения элементов в последовательности.

Разделение на части

Skip
Возвращает последовательность, в которой указанное число элементов пропущено.

SkipWhile
Возвращает последовательность, в которой пропущены элементы, не соответствующие указанному условию.

Take
Возвращает последовательность, в которую включается указанное число элементов.

TakeWhile
Возвращает последовательность, в которую включаются элементы, соответствующие указанному условию.

Проекция

Select
Создает проекцию части последовательности.

SelectMany
Создает проекцию части последовательности по принципу «один ко многим».

Кванторы

All
Определяет соответствие всех элементов последовательности указанным условиям.

Any
Определяет, есть ли в последовательность элементы, удовлетворяющие указанным условиям.

Contains
Определяет, есть ли в последовательности указанный элемент.

Ограничение

Where
Сортирует члены последовательности.

Настройка

Distinct
Возвращает последовательность без повторяющихся элементов.

Except
Возвращает последовательность, представляющую собой разность двух других последовательностей.

Intersect
Возвращает последовательность, представляющую собой пересечение двух других последовательностей.

Union
Возвращает последовательность, представляющую собой объединение двух других последовательностей.

вторник, 11 мая 2010 г.

XDocument в XMLDocument и наоборот

У меня в примерах
XmlDocument xmlDoc;
XDocument xDoc;

XMLDocument To XMLDocument

Самый простой, но и пожалуй самый медленный способ:
XDocument.Parse(xmlDoc.OuterXml);

Второй вариант:
using (var nodeReader = new XmlNodeReader(xmlDoc)) {
nodeReader.MoveToContent();
xDoc = XDocument.Load(nodeReader);
}

XMLDocument To XMLDocument

Очень простой способ:
xmlDoc.Load(xDoc.CreateReader());

И чего это я раньше следующим монстром пользовался?
using (MemoryStream memStr = new MemoryStream()) {
using (XmlWriter writer = XmlWriter.Create(memStr)) {
xDoc.Save(writer);
}
memStr.Position = 0;
using (XmlReader reader = XmlReader.Create(memStr)) {
xmlDoc.Load(reader);
}
}

вторник, 4 мая 2010 г.

Изменение имени проекта (сборки) в Visual Studio 2008

Вообще-то есть уже куча руководств, как можно проделать сие.

Например здесь.
http://social.msdn.microsoft.com/Forums/en-US/csharpide/thread/d4133fb7-57e1-44f2-a319-a63e7921ff0a

Но я решил запостить последовательность действий, которую выполнил я. При этом я не "поломал" проект и не потерял историю изменений для TFS. Итак VS 2008, TFS.

1. Выбрал проект в Експлорере проектов -> переименовал;
3. Свойства проекта -> Установил имя сборки и имя пространств имен. Тут же заглянул в информацию сборки и изменил название сборки (AssemblyInfo.cs);
4. В окне Quellcodeverwaltuns-Explorer переименовал папку. При этом проект закрылся и имя папки было на диске физически переименованно;
5. После того как открыл проект, студия ругнулась, что не нашла того самого проекта (или не смогла открыть). В эксплорере проектов он выделен другим цветом и пустой.
6. В свойствах проекта ранее доступное только для чтение свойство Projektordner становится доступным для изменения. Указал новый путь.

Все.

вторник, 23 марта 2010 г.

Автоматическое определение CultureInfo для установленных сателитных сборок

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

private List<CultureInfo> GetInstalledCultures() {
  // declare result
  List<CultureInfo> result = new List<CultureInfo>();
  // define paths
  String rootPath = Path.GetDirectoryName(this.GetType().Assembly.Location);
  String assemblyName = this.GetType().Assembly.GetName().Name;
  String satAssemblyName = assemblyName + ".resources.dll";
  // scan directory for sat assemblies
  DirectoryInfo root_di = new DirectoryInfo(rootPath);
  foreach (DirectoryInfo di in root_di.GetDirectories()) {
    String satAssemblyPath = Path.Combine(di.FullName, satAssemblyName);
    if (File.Exists(satAssemblyPath)) {
      try {
        // check that folder contains the correct data
        CultureInfo ci = new CultureInfo(di.Name);
        Assembly satAssembly = this.GetType().Assembly.GetSatelliteAssembly(ci);
        // successful
        result.Add(ci);
      }
      catch {
        // Nothing. Test for the creating the CultureInfo and Assembly objects;
      }
    }
  }
  // result
  return result;
}


* This source code was highlighted with Source Code Highlighter.

вторник, 12 января 2010 г.

Заполнение параметров значениями для SQL-выражения

Понадобилось протестировать созданное динамически SQL-выражение с параметрами, типа

Select * From Person
Where ID = @param

Чтобы выполнить такой запрос в окне запросов SQL Server Management Studio, необходимо объявить переменные-параметры и заполнить их значениями. Делается это так:

Declare @param uniqueidentifier
Set @param = '5792c959-33b4-47eb-a824-b74d32295506'

Также удалось использовать параметры следующих типов:

Строка:
DECLARE @param nvarchar(255)
SET @param = 'Dr%'

Целое число:
DECLARE @param int
SET @param = 123

Дата-время:
Declare @param DateTime
Set @param = '01/12/2010 14:02:17'

Управление узлами в TreeView (WinForms)

В данной статье представленны исходные коды для следующих операций управления узлами (TreeNode) в элементе управления TreeView:
1) Переместить узел вверх
2) Переместить узел вниз
3) Переместить узел в список родительских узлов
4) Переместить узел в список узлов вышестоящего узла

Речь идет о языке программирования C# и WinForms.

Вот интрефейс программы:




Обработчик кнопки для заполнения TreeView тестовыми элементами TreeNode (нижняя в правом углу):
int i = 0;
private void newNodeButton_Click(object sender, EventArgs e)
{
  // create node
  TreeNode newNode = new TreeNode(String.Format("Node {0}", i++));
  
  // add node in tree view
  if (treeView.SelectedNode != null)
    treeView.SelectedNode.Nodes.Add(newNode);
  else
    treeView.Nodes.Add(newNode);

}


* This source code was highlighted with Source Code Highlighter.

Вот код для определенных операций:

1) Узел вверх:
private void upButton_Click(object sender, EventArgs e)
{
  if (treeView.SelectedNode != null
    && treeView.SelectedNode.PrevNode != null)
  {
    // define edit collection
    TreeNodeCollection editNodes;
    if (treeView.SelectedNode.Parent != null)
      editNodes = treeView.SelectedNode.Parent.Nodes;
    else
      editNodes = treeView.Nodes;

    // define indexes
    int indexSelectedNode = treeView.SelectedNode.Index;
    int indexPreviousNode = treeView.SelectedNode.PrevNode.Index;

    // store node
    TreeNode selectedNode = treeView.SelectedNode;

    // swap
    editNodes.RemoveAt(indexSelectedNode);
    editNodes.Insert(indexPreviousNode, selectedNode);

    // select node
    treeView.SelectedNode = selectedNode;
  }
}


* This source code was highlighted with Source Code Highlighter.

2) Узел вниз:
private void downButton_Click(object sender, EventArgs e)
{
  if (treeView.SelectedNode != null
    && treeView.SelectedNode.NextNode != null)
  {
    // define edit collection
    TreeNodeCollection editNodes;
    if (treeView.SelectedNode.Parent != null)
      editNodes = treeView.SelectedNode.Parent.Nodes;
    else
      editNodes = treeView.Nodes;

    // define indexes
    int indexSelectedNode = treeView.SelectedNode.Index;
    int indexNextNode = treeView.SelectedNode.NextNode.Index;

    // store node
    TreeNode selectedNode = treeView.SelectedNode;

    // swap
    editNodes.RemoveAt(indexSelectedNode);
    editNodes.Insert(indexNextNode, selectedNode);

    // select node
    treeView.SelectedNode = selectedNode;
  }
}


* This source code was highlighted with Source Code Highlighter.

3) Узел влево:
private void leftButton_Click(object sender, EventArgs e)
{
  if (treeView.SelectedNode != null
    && treeView.SelectedNode.Parent != null)
  {

    // define edit collection
    TreeNodeCollection editNodes;
    if (treeView.SelectedNode.Parent.Parent != null)
      editNodes = treeView.SelectedNode.Parent.Parent.Nodes;
    else
      editNodes = treeView.Nodes;

    // store node
    TreeNode selectedNode = treeView.SelectedNode;

    // define indexes
    int indexSelectedNode = treeView.SelectedNode.Index;
    int indexParentNode = treeView.SelectedNode.Parent.Index;

    // move node
    treeView.SelectedNode.Parent.Nodes.Remove(selectedNode);
    editNodes.Insert(indexParentNode + 1, selectedNode);

    // select node
    treeView.SelectedNode = selectedNode;
  }
}


* This source code was highlighted with Source Code Highlighter.

4) Узел вправо:
private void rightButton_Click(object sender, EventArgs e)
{
  if (treeView.SelectedNode != null
    && treeView.SelectedNode.PrevNode != null)
  {

    // define edit collection
    TreeNodeCollection editNodes;
    if (treeView.SelectedNode.Parent != null)
      editNodes = treeView.SelectedNode.Parent.Nodes;
    else
      editNodes = treeView.Nodes;

    // store node
    TreeNode selectedNode = treeView.SelectedNode;
    TreeNode previousNode = selectedNode.PrevNode;

    // move node
    editNodes.Remove(selectedNode);
    previousNode.Nodes.Add(selectedNode);

    // select node
    treeView.SelectedNode = selectedNode;
  }
}


* This source code was highlighted with Source Code Highlighter.

Интрефейс пользователя подсказывает, какие операции доступны для выбранного элемента. Об этом заботится следующая функция:
private void updateEnablingButtons()
{
  upButton.Enabled = (treeView.SelectedNode != null
    && treeView.SelectedNode.PrevNode != null);

  downButton.Enabled = (treeView.SelectedNode != null
    && treeView.SelectedNode.NextNode != null);

  leftButton.Enabled = (treeView.SelectedNode != null
    && treeView.SelectedNode.Parent != null);

  rightButton.Enabled = (treeView.SelectedNode != null
    && treeView.SelectedNode.PrevNode != null);
}


* This source code was highlighted with Source Code Highlighter.

Ее вызываю в момент создания формы и по событию AfterSelect элемента управления TreeView

воскресенье, 3 января 2010 г.

Regex. Поиск слова между кавычками

Дана строка:
что-то здесь Ключ1="Значение" Ключ2="Другое значение" здесь еще кой-чего.

Найти значение первого ключа без кавычек:
^.*Ключ1="(?<1>([.]|[^"])*)".*$

Результат:
Значение