<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Техно-логи</title>
	<atom:link href="http://www.kurdyukov.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.kurdyukov.com</link>
	<description>Заметки о разработке и прочей жизни</description>
	<lastBuildDate>Sun, 13 May 2012 08:34:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>Еще один software as website</title>
		<link>http://www.kurdyukov.com/2012/05/13/appjs/</link>
		<comments>http://www.kurdyukov.com/2012/05/13/appjs/#comments</comments>
		<pubDate>Sun, 13 May 2012 08:34:17 +0000</pubDate>
		<dc:creator>alik</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://www.kurdyukov.com/?p=235</guid>
		<description><![CDATA[В новостях Y Combinator проскочило упоминание очередного варианта реализации фреймворка для создания десктопных приложений на HTML5+CSS+JS. Этот проект называется AppJs. Система строится на основе Node.js. На момент написания поста, проект имеет версию 0.0.2. Базовое открытие окон сделано только для Linux и немного для Windows. Для Mac пока ничего не работает. Исходники на GitHub. Никакой большой [...]]]></description>
			<content:encoded><![CDATA[<p>В новостях Y Combinator проскочило упоминание очередного варианта реализации фреймворка для создания десктопных приложений на HTML5+CSS+JS. Этот проект называется <a href="http://appjs.org/" title="AppJs" target="_blank">AppJs</a>.</p>
<p>Система строится на основе Node.js. На момент написания поста, проект имеет версию 0.0.2. Базовое открытие окон сделано только для Linux и немного для Windows. Для Mac пока ничего не работает. Исходники на GitHub.</p>
<p>Никакой большой коммерческой организации за проектом не замечено. Лицения MIT.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kurdyukov.com/2012/05/13/appjs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Слава ReSharper-у!</title>
		<link>http://www.kurdyukov.com/2012/05/07/glory-to-resharper/</link>
		<comments>http://www.kurdyukov.com/2012/05/07/glory-to-resharper/#comments</comments>
		<pubDate>Mon, 07 May 2012 11:31:32 +0000</pubDate>
		<dc:creator>alik</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[ReSharper]]></category>
		<category><![CDATA[vs.net]]></category>

		<guid isPermaLink="false">http://www.kurdyukov.com/?p=226</guid>
		<description><![CDATA[Некоторое время с мучался с тем, что в VisualStudio 2010 невозможно быстро перейти в чужие исходники. Надо было выкачивать, подключать и т.п. Но сегодня я внимательно посмотрел на окно ReSharper -> Options -> External Sources. И, о чудо, там есть галочка &#171;Allow downloading from external locations&#187;! Для библиотеки Nancy, с которой я сейчас вожусь, исходники [...]]]></description>
			<content:encoded><![CDATA[<p>Некоторое время с мучался с тем, что в VisualStudio 2010 невозможно быстро перейти в чужие исходники. Надо было выкачивать, подключать и т.п.</p>
<p>Но сегодня я внимательно посмотрел на окно ReSharper -> Options -> External Sources. И, о чудо, там есть галочка &laquo;Allow downloading from external locations&raquo;! Для библиотеки Nancy, с которой я сейчас вожусь, исходники оказались, что мне сильно помогло. Буду надеяться с остальными опен-сорсными либами ситуация будет аналогичная.</p>
<p>И пожелание к JetBrains напоследок &#8211; сделайте, пожалуйста, напоминалку про эту фичу при переходе на дизассемблер чужих либов.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kurdyukov.com/2012/05/07/glory-to-resharper/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Интеграция Atlassian Bamboo и тестов xUnit.net</title>
		<link>http://www.kurdyukov.com/2012/02/18/atlassian-bamboo-xunit-net/</link>
		<comments>http://www.kurdyukov.com/2012/02/18/atlassian-bamboo-xunit-net/#comments</comments>
		<pubDate>Fri, 17 Feb 2012 22:51:05 +0000</pubDate>
		<dc:creator>alik</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[vs.net]]></category>
		<category><![CDATA[xUnit.net]]></category>

		<guid isPermaLink="false">http://www.kurdyukov.com/?p=206</guid>
		<description><![CDATA[Система непрерывной интеграции Atlassiat Bamboo включает множество плагинов для работы с тестами, но поддержка xUnit.net в это множество, к сожалению, не входит. Но интеграция все же возможна, о ней и расскажем. Итак, имеется solution, состоящий из множества проектов. Проекты, которые собираются в assembly, и названия которых заказчиваются на Tests являются комплектами xUnit тестов. Сборка всего [...]]]></description>
			<content:encoded><![CDATA[<p>Система непрерывной интеграции Atlassiat Bamboo включает множество плагинов для работы с тестами, но поддержка xUnit.net в это множество, к сожалению, не входит. Но интеграция все же возможна, о ней и расскажем.</p>
<p>Итак, имеется solution, состоящий из множества проектов. Проекты, которые собираются в assembly, и названия которых заказчиваются на Tests являются комплектами xUnit тестов. Сборка всего решения построена на MSBuild, осуществляется сервером Bamboo. Для управления внешними сбоками используется NuGet.<br />
<span id="more-206"></span></p>
<h2>Шаг 1: Подключение xunit в MSBuild</h2>
<p>При установке сборок xUnit в проект через NuGet, сборка задачи xunit для MSBuild уже была закачана. Подключим ее к нашему MSBuild проекту.</p>
<pre class="brush: xml; title: ; notranslate">
  &lt;UsingTask
      AssemblyFile=&quot;packages\xunit.1.9.0.1566\lib\xunit.runner.msbuild.dll&quot;
      TaskName=&quot;Xunit.Runner.MSBuild.xunit&quot;/&gt;
</pre>
<p>Если вы не используете NuGet, вы можете скачать дистрибутив xunit и положить .dll самостоятельно.</p>
<h2>Шаг 2: Подготовка преобразования</h2>
<p>В составе поставки Bamboo поддержки xUnit нет, но имеется job task под название NUnit parse. А в поставке xunit имеется описание трансформации лога xUnit в формат NUnit. Воспользуемся этим. Для этого надо скопировать файл NUnitXml.xsl из поставки xunit в корень проекта.</p>
<h2>Шаг 3: Добавление задач в скрипт сборки</h2>
<p>Теперь надо добавить 2 таргета в скрипт сборки:</p>
<pre class="brush: xml; title: ; notranslate">
  &lt;Target Name=&quot;Test&quot; DependsOnTargets=&quot;TestClean&quot;&gt;
    &lt;ItemGroup&gt;
      &lt;TestAssemblies Include=&quot;$(MSBuildProjectDirectory)\*\bin\$(Configuration)\*Tests.dll&quot;/&gt;
    &lt;/ItemGroup&gt;

    &lt;xunit Assembly=&quot;@(TestAssemblies)&quot; Xml=&quot;%(RelativeDir)%(TestAssemblies.FileName).xunit&quot; ContinueOnError=&quot;true&quot; Condition=&quot;'@(TestAssemblies)' != ''&quot;/&gt;

    &lt;ItemGroup&gt;
      &lt;TestReports Include=&quot;$(MSBuildProjectDirectory)/*/bin/$(Configuration)/*Tests.xunit&quot;/&gt;
    &lt;/ItemGroup&gt;
    &lt;XslTransformation XmlInputPaths=&quot;@(TestReports)&quot; OutputPaths=&quot;%(RelativeDir)%(TestReports.FileName).nunit.xml&quot;
                        XslInputPath=&quot;NUnitXml.xslt&quot; Condition=&quot;'@(TestReports)' != ''&quot;/&gt;
  &lt;/Target&gt;

  &lt;Target Name=&quot;TestClean&quot; AfterTargets=&quot;Clean&quot;&gt;
    &lt;ItemGroup&gt;
      &lt;CleanReports Include=&quot;$(MSBuildProjectDirectory)/*/bin/$(Configuration)/*Tests.xunit&quot;/&gt;
      &lt;CleanReports Include=&quot;$(MSBuildProjectDirectory)/*/bin/$(Configuration)/*Tests.nunit.xml&quot;/&gt;
    &lt;/ItemGroup&gt;
    &lt;Delete Files=&quot;@(CleanReports)&quot; TreatErrorsAsWarnings=&quot;true&quot;/&gt;
  &lt;/Target&gt;
</pre>
<p>После добавление таргетов, вам надо будет настройки использование таргета Test в сбоке на Bamboo. У меня это делается настройками по умолчанию, примерно так:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;Project ToolsVersion=&quot;4.0&quot; xmlns=&quot;http://schemas.microsoft.com/developer/msbuild/2003&quot;
         InitialTargets=&quot;ValidateSolutionConfiguration;ValidateToolsVersions;ValidateProjects&quot; DefaultTargets=&quot;Clean;Build;Test&quot;&gt;
</pre>
<blockquote><p>NB! Важно, что файл отчета формата NUnit должен иметь расширение xml, иначе его не найдет NUnit Parse Task.
</p></blockquote>
<h2>Шаг 4: Настройка парсинга в Bamboo</h2>
<p>После задачи сборки проекта добавляем задачу NUnit Parsing. Примерно так:<br />
<a href="http://www.kurdyukov.com/wp-content/uploads/2012/02/nunit-task.png"><img src="http://www.kurdyukov.com/wp-content/uploads/2012/02/nunit-task.png" alt="" title="Конфигурация NUnit Parsing" width="912" class="alignnone size-full wp-image-207" /></a><br />
До этого интерфейса можно добраться:</p>
<ul>
<li>выбрав план сборки,</li>
<li>нажав на configure,</li>
<li>потом выбрав job сборки.</li>
<ul>
<h2>Проверка</h2>
<p>Запустите план на сборку и убедитесь, в том, что тесты поключились и отчет виден через интерфейс Bamboo.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kurdyukov.com/2012/02/18/atlassian-bamboo-xunit-net/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Правила оформления кода C# v1.0</title>
		<link>http://www.kurdyukov.com/2012/02/07/c-sharp-code-style/</link>
		<comments>http://www.kurdyukov.com/2012/02/07/c-sharp-code-style/#comments</comments>
		<pubDate>Tue, 07 Feb 2012 04:11:21 +0000</pubDate>
		<dc:creator>alik</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[c#]]></category>

		<guid isPermaLink="false">http://www.kurdyukov.com/?p=192</guid>
		<description><![CDATA[Сейчас я занимаюсь проектом, который разрабатывался достаточно большое время, но в разработке не применялось никаких правил оформления кода. Поскольку так жить нельзя, считаю важным привести свое видение того, как имеет смысл оформлять код на C#. Использование такого стиля позволяет: Быстро ориентироваться Не задумываться над оформлением Применять автоматические инструменты контроля стиля (ReSharper) Описание рассчитано на использование [...]]]></description>
			<content:encoded><![CDATA[<p>Сейчас я занимаюсь проектом, который разрабатывался достаточно большое время, но в разработке не применялось никаких правил оформления кода. Поскольку так жить нельзя, считаю важным привести свое видение того, как имеет смысл оформлять код на C#.</p>
<p>Использование такого стиля позволяет:</p>
<ol>
<li>Быстро ориентироваться</li>
<li>Не задумываться над оформлением</li>
<li>Применять автоматические инструменты контроля стиля (ReSharper)</li>
</ol>
<p>Описание рассчитано на использование C# версии 3.5.<br />
<span id="more-192"></span></p>
<h2>Переменные</h2>
<p>Использовать значимые имена переменных написанных на правильном английском. Транслитерация названий переменных не допускается.<br />
Хорошо:</p>
<pre class="brush: csharp; title: ; notranslate">
private int letters;
private int result;
</pre>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
private int rezultat;
private int oshibka;
</pre>
<p>Применение венгерской нотации не применяется ни в каких участках кода, ни в GUI, ни в DataAccess, ни в доменной части.<br />
Хорошо:</p>
<pre class="brush: csharp; title: ; notranslate">
private int letters;
private string result;
</pre>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
private int iRezultat;
private ComboBox cbItems;
</pre>
<p>В именах переменных не допускается применение знака подчеркивания. Каждое новое слово пишется с прописной буквы.<br />
Хорошо:</p>
<pre class="brush: csharp; title: ; notranslate">
private int lettersToUpdate;
private string lastName;
</pre>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
private int rows_in_table;
private string last_Name;
</pre>
<p>Переменные не могут начинаться со знака подчеркивания.<br />
Хорошо:</p>
<pre class="brush: csharp; title: ; notranslate">
private int lettersToUpdate;
private string lastName;
</pre>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
private int _rows;
private string _lastName;
</pre>
<p>Только переменные видные извне класса начинаются с прописной буквы. Все остальные типы внутренних переменных начинаются со строчных букв.</p>
<p>Хорошо:</p>
<pre class="brush: csharp; title: ; notranslate">
public static int Letters;
public int Letters;
protected int Letters;
internal int Letters;
</pre>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
public static int letters;
public static int LETTERS;
public static int LeTTeRs;
</pre>
<p>Переменные должны быть понятными, использование однобуквенных переменных допускается только в циклах и порой в лямбда-функциях.</p>
<p>Хорошо:</p>
<pre class="brush: csharp; title: ; notranslate">
public static int Letters;
</pre>
<pre class="brush: csharp; title: ; notranslate">
for (var i = 0; i &lt; names.Count; i++) {
...
}
</pre>
<pre class="brush: csharp; title: ; notranslate">
names.Where(s =&gt; s.Length &gt; 3).Select(s =&gt; s);
</pre>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
private int n;
private List&lt;string&gt; l;
</pre>
<p>Все эти методы направлены на то, чтобы разработчики уделяли больше внимания на фактическое назначение кода. Чтение кода с реальными именами заставляет думать в терминах процесса, а не абстрактного явления. Более того, такой код становится самодокументирующимся.</p>
<h2>Использование var</h2>
<p>Использование var в коде допускается. Наличие syntax sugar в виде var помогает меньше печатать, но иногда заставляет задуматься о типе переменной, что снижает скорость работы.</p>
<h2>Именование методов</h2>
<p>Все методы начинаются с прописной буквы и не содержат в своем названии знака подчеркивания.<br />
Хорошо:</p>
<pre class="brush: csharp; title: ; notranslate">
private int GetErrorMessages() {
   …
}
</pre>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
private int get_Error_Messages() {
   …
}

private void save_OnClick(…) {
   …
}
</pre>
<p>Имена методов должны быть написаны на английском языке. Транслитерация не допускается.<br />
Хорошо:</p>
<pre class="brush: csharp; title: ; notranslate">
private int GetStockRates () {
   …
}
</pre>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
private int GetKotirovki () {
   …
}
</pre>
<p>Первым словом в названии метода должен быть глагол.<br />
Хорошо:</p>
<pre class="brush: csharp; title: ; notranslate">
private int LoadStocks() {
   …
}
</pre>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
private int StocksLoad() {
   …
}
</pre>
<p>Можно использовать универсальные глаголы типа Do или Perform.</p>
<p>Именование методов при возвращении булевого значения не должно формулироваться отрицательно.<br />
Хорошо:</p>
<pre class="brush: csharp; title: ; notranslate">
private bool IsValidUser () {
   …
}
</pre>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
private bool IsUserDoNotHaveErrors () {
   …
}
</pre>
<p>Данные правила направлены на согласованность методов с самим фреймворком, и легкость чтения и понимания.</p>
<h2>Обрамление кода</h2>
<p>В коде не должно быть регионов (regions), разделения кусков кода комментариями в виде строки и прочее. Все это указывает только на то, что вы написали плохой код, который без вспомогательных средств невозможно прочитать и понять.</p>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
#region public fields

public static int Letters;

#endregion

//======== public fields =========================================

public static int Letters;

//======== end public fields =========================================
</pre>
<h2>Комментарии</h2>
<p>В коде не должно быть логики закрытой комментариями. Такие куски смущают других программистов в случае поиска ошибки и во время чтения программы. Откат к переписанному или удаленному коду осуществляется через средства системы контроля исходного кода. Вся логика закрытая комментариями должна быть удалена немедленно.</p>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
//        public Foo() {
//            Letters = 2;
//        }
</pre>
<p>Не стоит комментировать каждую строку и писать очевидные вещи.</p>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
/// &lt;summary&gt;
/// Отображение данных
/// &lt;/summary&gt;
public interface IDataViewer
{
    /// &lt;summary&gt;
    /// Всегда один
    /// &lt;/summary&gt;
    bool IsSingle { get; }

    /// &lt;summary&gt;
    /// Сервер
    /// &lt;/summary&gt;
    string HostName { get; set; }

    /// &lt;summary&gt;
    /// База данных
    /// &lt;/summary&gt;
    string Database { get; set; }

    /// &lt;summary&gt;
    /// Загрузка данных
    /// &lt;/summary&gt;
    /// &lt;returns&gt;Результат загрузки&lt;/returns&gt;
    bool LoadData();
}
</pre>
<p>Комментарии стоит писать на английском языке, тогда вышеозначенной ситуации можно было бы избежать, так как сразу видна вся абсурдность комментария. Дополнительным плюсом будет то, что вы не так сильно будете забывать английский язык.</p>
<h2>Оформление блоков кода</h2>
<p>Фигурная открывающая скобка всегда стоит на следующей от конструкции языка строке.<br />
Хорошо:</p>
<pre class="brush: csharp; title: ; notranslate">
namespace N
{
    internal interface I
    {
        void foo();
    }

    internal class C
    {}
}
</pre>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
namespace N {
    internal interface I {
        void foo();
    }

    internal class C {}
}
</pre>
<p>Такой подход позволяет записывать код более компактно и боле четко разграничивать методы визуально.</p>
<h2>Свойства</h2>
<p>Автосвойства должны быть записаны в одну строку.</p>
<p>Хорошо:</p>
<pre class="brush: csharp; title: ; notranslate">
public int Age { get; set; }
public string Login { get; set; }
</pre>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
public int Age {
    get;
    set;
}
public string Login {
    get;
    set;
}
</pre>
<p>В остальном правила такие же, как и для полей класса.</p>
<h2>Логические операции</h2>
<p>Длина строки с логическими операциями не должна превышать 80-120 символов. Перенос операций производится с логическим знаком.</p>
<p>Хорошо:</p>
<pre class="brush: csharp; title: ; notranslate">
if(boolValue &amp;&amp; number &gt;= 0) {
   ...
}

if(string.IsNullOrWhiteSpace(bigCompositeCaption)
   &amp;&amp; bigCompositeCaption.StartsWith(&quot;x00&quot;)
   &amp;&amp; bigCompositeCaption.Length &gt; somePositiveNumber) {
     ...
}
</pre>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
if(string.IsNullOrWhiteSpace(bigCompositeCaption) &amp;&amp;
   bigCompositeCaption.StartsWith(&quot;x00&quot;) &amp;&amp;
   bigCompositeCaption.Length &gt; somePositiveNumber) {
     ...
}

if(string.IsNullOrWhiteSpace(bigCompositeCaption) &amp;&amp; bigCompositeCaption.StartsWith(&quot;x00&quot;) &amp;&amp; bigCompositeCaption.Length &gt; somePositiveNumber) {
    ...
}
</pre>
<p>Форматирование тернарной операции должно быть на несколько строк.</p>
<p>Хорошо:</p>
<pre class="brush: csharp; title: ; notranslate">
return boolValue
    ? somePositiveNumber
    : anotherNegativeNumber;
</pre>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
return boolValue ? somePositiveNumber : anotherNegativeNumber;
</pre>
<p>Исключение может быть сделано только для результатов в 1-3 символа.</p>
<p>Хорошо:</p>
<pre class="brush: csharp; title: ; notranslate">
return boolValue ? 1 : -1;

return boolValue ? “Y” : “N”;
</pre>
<p>Унарная операция ?? так же должна быть с переносом на новую строку, если для записи выражения требуется более ~60 символов.</p>
<p>Хорошо:</p>
<pre class="brush: csharp; title: ; notranslate">
return someVeryLongNamedNullable() ?? “N/A”;

return someVeryLongNamedNullable()
    ?? new SomeVeryLongNamedClass();
</pre>
<p>Плохо:</p>
<pre class="brush: csharp; title: ; notranslate">
return someVeryLongNamedNullable() ?? new SomeVeryLongNamedClass();
</pre>
<p>Строка начинающаяся со знака логической операции показывает, что это все еще идет условие, а не первый оператор при выполнении условия. Сравните:</p>
<pre class="brush: csharp; title: ; notranslate">
if(string.IsNullOrWhiteSpace(bigCompositeCaption) &amp;&amp;
   bigCompositeCaption.StartsWith(&quot;x00&quot;) &amp;&amp;
   bigCompositeCaption.Length &gt; somePositiveNumber)
   bigCompositeCaption.Trim();

if(string.IsNullOrWhiteSpace(bigCompositeCaption)
   &amp;&amp; bigCompositeCaption.StartsWith(&quot;x00&quot;)
   &amp;&amp; bigCompositeCaption.Length &gt; somePositiveNumber)
   bigCompositeCaption.Trim();
</pre>
<p>Специально подобран такой пример, когда в условии используется та же переменная. При договоренности, что перенос условия начинается с логических знаков, легче найти начало блока.</p>
<p>Хочется поблагодарить коллегу violet-tape за его аналогичное <a href="http://www.rootfront.com/article/740801/2011-08-10/pravila-oformlenija-koda-c-v1_0" title="http://www.rootfront.com/article/740801/2011-08-10/pravila-oformlenija-koda-c-v1_0" target="_blank">состав правил</a>. Множество правил было взято именно у него.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kurdyukov.com/2012/02/07/c-sharp-code-style/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Автоматическая реализация INotifyPropertyChanged на Spring.NET</title>
		<link>http://www.kurdyukov.com/2012/02/04/spring-inotifypropertychanged/</link>
		<comments>http://www.kurdyukov.com/2012/02/04/spring-inotifypropertychanged/#comments</comments>
		<pubDate>Sat, 04 Feb 2012 01:34:55 +0000</pubDate>
		<dc:creator>alik</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[Spring.NET]]></category>

		<guid isPermaLink="false">http://www.kurdyukov.com/?p=188</guid>
		<description><![CDATA[В статье ранее я писал как сделать автоматическую реализацию INotifyPropertyChanged на основе расширений библиотеки NInject. К сожалению, моя жизнь с этой библиотекой не сложилась, NInject был заменен на Spring.NET. При этом схему автореализации надо было как-то перенести без особенных изменений прикладного кода. Объясню, что именно я сделал. Для начала нам нужен интерфейс, который будет реализовываться [...]]]></description>
			<content:encoded><![CDATA[<p>В статье <a href="http://www.kurdyukov.com/2012/01/31/aop-inotifypropertychanged/" title="Простая реализация INotifyPropertyChanged" target="_blank">ранее</a> я писал как сделать автоматическую реализацию INotifyPropertyChanged на основе расширений библиотеки NInject. К сожалению, моя жизнь с этой библиотекой не сложилась, NInject был заменен на Spring.NET. При этом схему автореализации надо было как-то перенести без особенных изменений прикладного кода. Объясню, что именно я сделал.</p>
<p><span id="more-188"></span><br />
Для начала нам нужен интерфейс, который будет реализовываться всеми потенциальными автонотифицируемыми классами:</p>
<pre class="brush: csharp; title: ; notranslate">
    public interface IAutoNotifyPropertyChanged : INotifyPropertyChanged
    {
        void OnPropertyChanged(string propertyName);
    }
</pre>
<p>Удобства ради можно использовать базовый класс для всех авто-реализаций:</p>
<pre class="brush: csharp; title: ; notranslate">
    public class ViewModelBase : IAutoNotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
</pre>
<p>Кроме этого, нам понадобятся атрибуты, которыми мы будет включать/отключать авто-нотификацию:</p>
<pre class="brush: csharp; title: ; notranslate">
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class NotifyOfChangesAttribute : Attribute
    {
    }
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
    public class DoNotNotifyOfChangesAttribute : Attribute
    {
    }
</pre>
<p>Теперь пришла очередь Pointcut, которые будет определять setter-ы целевых свойств:</p>
<pre class="brush: csharp; title: ; notranslate">
    public class AutoNotifyPointcut : StaticMethodMatcherPointcut
    {
        public override bool Matches(MethodInfo method, Type targetType)
        {
            if (!typeof(IAutoNotifyPropertyChanged).IsAssignableFrom(targetType))
                return false;

            // non-setters ignored
            if (!method.Name.StartsWith(&quot;set_&quot;))
                return false;

            object[] attributes = targetType.GetCustomAttributes(typeof(NotifyOfChangesAttribute), true);
            if (attributes.Length &gt; 0)
            {
                object[] disables = method.GetCustomAttributes(typeof (DoNotNotifyOfChangesAttribute), true);
                if (disables.Length &gt; 0)
                    return false;

                return true;
            }

            attributes = method.GetCustomAttributes(typeof (NotifyOfChangesAttribute), true);
            return attributes.Length &gt; 0;
        }
    }
</pre>
<p>Затем нам нужен advice, в котором и будет происходить вся работа:</p>
<pre class="brush: csharp; title: ; notranslate">
    public class AfterPropertySetAdvice : IMethodInterceptor
    {
        private static readonly Logger logger = LogManager.GetCurrentClassLogger();

        public object Invoke(IMethodInvocation invocation)
        {
            object proxy = invocation.Proxy;
            string name = null;

            IAutoNotifyPropertyChanged model = proxy as IAutoNotifyPropertyChanged;
            if (model == null)
            {
                logger.Error(&quot;Advice is called on non-IAutoNotifyPropertyChanged class&quot;);
            }
            else
            {
                name = invocation.Method.Name;
                if (!name.StartsWith(&quot;set_&quot;))
                {
                    logger.Error(&quot;Cannot notify on non-setter&quot;);
                }
                name = name.Substring(4);
            }

            object rval = invocation.Proceed();

            if (name != null)
            {
                model.OnPropertyChanged(name);
            }

            return rval;
        }
    }
</pre>
<p>Тут для вящего удобсва отладки используется NLog. Его использование можно вовсе удалить.</p>
<p>Так, классы созданы, надо как-то их применить к объектам. Сразу скажу, что из-за особенностей Spring AOP для оборачивания класса в advice надо, чтобы экземпляр класса создавался Spring-ом. Код подключения выглядит примерно так:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
&lt;objects xmlns=&quot;http://www.springframework.net&quot;&gt;
  &lt;object id=&quot;notifyOnChangePointcut&quot; type=&quot;CommonControls.AutoNotify.AutoNotifyPointcut, CommonControls&quot;/&gt;
  &lt;object id=&quot;afterPropertySetAdvice&quot; type=&quot;CommonControls.AutoNotify.AfterPropertySetAdvice, CommonControls&quot;/&gt;

  &lt;object id=&quot;notifyInterceptor&quot; type=&quot;Spring.Aop.Support.DefaultPointcutAdvisor, Spring.Aop&quot;&gt;
    &lt;property name=&quot;Pointcut&quot; ref=&quot;notifyOnChangePointcut&quot;/&gt;
    &lt;property name=&quot;Advice&quot; ref=&quot;afterPropertySetAdvice&quot;/&gt;
  &lt;/object&gt;

  &lt;object type=&quot;Spring.Aop.Framework.AutoProxy.InheritanceBasedAopConfigurer, Spring.Aop&quot;&gt;
    &lt;property name=&quot;ProxyDeclaredMembersOnly&quot; value=&quot;false&quot;/&gt;
    &lt;property name=&quot;ObjectNames&quot;&gt;
      &lt;list&gt;
        &lt;value&gt;*Model&lt;/value&gt;
      &lt;/list&gt;
    &lt;/property&gt;
    &lt;property name=&quot;InterceptorNames&quot;&gt;
      &lt;list&gt;
        &lt;value&gt;notifyInterceptor&lt;/value&gt;
      &lt;/list&gt;
    &lt;/property&gt;
  &lt;/object&gt;
&lt;/objects&gt;
</pre>
<p>Можно заметить, что оборачиванию будут подвергнуты объекты, id которых заканчивается на &laquo;Model&raquo;. Анонимные объекты будет проигнорированы.</p>
<p>Кажется, что ограничение по имени какое-то странное. Также кажется, что использование InheritanceBasedAopConfigurer выглядит странно в контексте наличия тега aop:config в Spring.NET. Поясню, почему именно так.</p>
<p>В рамках Spring.NET существует 3 способо создания proxy объектов для вызова advice:</p>
<ol>
<li>Aggregation based &#8211; для объекта-обертки генерируется DynamicProxy со своим интерфейсом. Такой объект нельзя привести к оригинальному типу target объекта. Реальный объект в этом случае будет аггрегирован внутри proxy. Нам не подходит из-за несовместимого интерфейса.</li>
<li>Inheritance based &#8211; объект-прокси будет наследником класса target объекта, при этом обернуты будут только virtual методы и свойства оригинала. Оригинальный объект будет аггрегирован внутри proxy. В нашем случае это дает интересный спец-эффект: поскольку события тоже проксируются, то добавление обработчика события на объект-обертку не влияет на оригинальный объект. Значит, если внутри advice вызвать событие, то вызов будет превращен в вызов объекта-оригинала, а не обертки. А на внутреннем объекте обработчиков как небыло так и нет. Значит, тоже не подходит</li>
<li>InheritanceBasedAopConfigurer &#8211; новый способ генерации вызовов, добавленный в Spring 1.2. Идея состоит в изменении кода оригинального объекта. Вот это нам подходит, но дает указанные выше ограничения на создание объектов</li>
</ol>
<p>Пример создания объекта:</p>
<pre class="brush: xml; title: ; notranslate">
  &lt;object id=&quot;mainModel&quot; type=&quot;DataServer.ViewModel.RetranslatingDataServerManagerModel, DataServer&quot;/&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.kurdyukov.com/2012/02/04/spring-inotifypropertychanged/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Неопределенное будущее Titanium Desktop</title>
		<link>http://www.kurdyukov.com/2012/02/01/titanium-desktop-future/</link>
		<comments>http://www.kurdyukov.com/2012/02/01/titanium-desktop-future/#comments</comments>
		<pubDate>Wed, 01 Feb 2012 01:42:39 +0000</pubDate>
		<dc:creator>alik</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Titanium]]></category>

		<guid isPermaLink="false">http://www.kurdyukov.com/?p=180</guid>
		<description><![CDATA[Около полугода я следил на развитием проекта Titanium Desktop. Идея продукта состоит в том, что можно создавать полноценные desktop приложения на HTML+JS. Я подумывал использовать этот фреймворк в одном из своих проектов. Но сегодня, проверяя новости, обнаружил нерадостное &#8211; проект снимают с финансирования AppCelerator и передают сообществу разработчиков. Официальный пресс-релиз можно прочитать здесь. Все это [...]]]></description>
			<content:encoded><![CDATA[<p>Около полугода я следил на развитием проекта <a href="http://www.appcelerator.com/products/titanium-desktop-application-development/" title="http://www.appcelerator.com/products/titanium-desktop-application-development/" target="_blank">Titanium Desktop</a>. Идея продукта состоит в том, что можно создавать полноценные desktop приложения на HTML+JS. Я подумывал использовать этот фреймворк в одном из своих проектов. Но сегодня, проверяя новости, обнаружил нерадостное &#8211; проект снимают с финансирования AppCelerator и передают сообществу разработчиков. Официальный пресс-релиз можно прочитать <a href="http://developer.appcelerator.com/blog/2012/01/the-future-of-titanium-desktop.html" title="http://developer.appcelerator.com/blog/2012/01/the-future-of-titanium-desktop.html" target="_blank">здесь</a>.</p>
<p>Все это означает, что проект может приостановиться на неопределенный срок. А значит надо будет взвесить все &laquo;за&raquo; и &laquo;против&raquo; прежде чем использовать.</p>
<p>В качестве альтернативы предлагается <a href="http://code.google.com/p/chromiumembedded/" title="http://code.google.com/p/chromiumembedded/" target="_blank">chromiumembedded</a>, который тоже находится в непонятном состоянии. По этому проекту даже с документацией есть проблемы, вся поддержка &#8211; через полуживой форум.</p>
<p>Таким образом, многоплатформенных технологий для создания desktop приложений на HTML+JS в доступности не видно. Разве что Adobe AIR, но он пугает чем, что Adobe.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kurdyukov.com/2012/02/01/titanium-desktop-future/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Простая реализация INotifyPropertyChanged</title>
		<link>http://www.kurdyukov.com/2012/01/31/aop-inotifypropertychanged/</link>
		<comments>http://www.kurdyukov.com/2012/01/31/aop-inotifypropertychanged/#comments</comments>
		<pubDate>Tue, 31 Jan 2012 01:10:34 +0000</pubDate>
		<dc:creator>alik</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[INotifyPropertyChanged]]></category>

		<guid isPermaLink="false">http://www.kurdyukov.com/?p=168</guid>
		<description><![CDATA[При разработке для платформы .NET часто приходится делать так раздражающие всех реализации интерфейса INotifyPropertyChanged на классах-моделях. Типичный пример выглядит так: На мой взгляд, с этим кодом есть 2 проблемы: Очень много повторений и кода вызванного необходимостью вызвать NotifyPropertyChanged. Увеличивается количество &#171;тупой&#187; работы. Использование строковой константы Name в качестве аргумента. Рефакторинг может привести к разрушению биндинга [...]]]></description>
			<content:encoded><![CDATA[<p>При разработке для платформы .NET часто приходится делать так раздражающие всех реализации интерфейса <code>INotifyPropertyChanged</code> на классах-моделях. Типичный пример выглядит так:</p>
<pre class="brush: csharp; title: ; notranslate">
class StatisticsRecord: INotifyPropertyChanged
{
    private string name;
    public string Name { get { return name; } set { name = value; NotifyPropertyChanged(&quot;Name&quot;); } }	

    private void NotifyPropertyChanged(string name)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(name));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}
</pre>
<p>На мой взгляд, с этим кодом есть 2 проблемы:</p>
<ol>
<li>Очень много повторений и кода вызванного необходимостью вызвать <code> NotifyPropertyChanged</code>. Увеличивается количество &laquo;тупой&raquo; работы.</li>
<li>Использование строковой константы Name в качестве аргумента. Рефакторинг может привести к разрушению биндинга к такому свойству.</li>
</ol>
<p><span id="more-168"></span><br />
По счастью разработчики симпатичного фреймворка <a href="http://http://ninject.org/" title="http://ninject.org/" target="_blank">NInject</a> сделали расширение <a href="https://github.com/ninject/ninject.extensions.interception" title="https://github.com/ninject/ninject.extensions.interception" target="_blank">Ninject.Extensions.Interception</a>, которое позволяет решить описанные выше проблемы за счет использования динамического AOP. Используется это так:</p>
<ol>
<li>Подключаем к проекту библиотеки NInject, Ninject.Extensions.Interception, Castle.Core, Ninject.Extensions.Interception.DynamicProxy</li>
<li>Создаем класс-реализацию интерфейса IAutoNotifyPropertyChanged, например так:
<pre class="brush: csharp; title: ; notranslate">
public class ViewModelBase : IAutoNotifyPropertyChanged
{
     public event PropertyChangedEventHandler PropertyChanged;

     public void OnPropertyChanged(string propertyName)
     {
         PropertyChangedEventHandler handler = PropertyChanged;
         if (handler != null)
         {
             handler(this, new PropertyChangedEventArgs(propertyName));
         }
     }
}
</pre>
</li>
<li>Используем этот класс в нашем классе модели. Например:
<pre class="brush: csharp; title: ; notranslate">
[NotifyOfChanges]
class StatisticsRecord: INotifyPropertyChanged
{
    public virtual string Name { get; set; }

    [DoNotNotifyOfChanges]
    public virtual string NonNotifyableProperty { get; set; }
}
</pre>
<blockquote><p><strong>NB!</strong> Важно, чтобы getter-ы и setter-ы были виртуальными, поскольку мы используем DynamicProxy для добавления нотификаций
</p></blockquote>
</li>
<li>Подключаем &laquo;перехватчик&raquo; при конфигурации ядра NInject:
<pre class="brush: csharp; title: ; notranslate">
...
kernel.Components.Add&lt;IPlanningStrategy, AutoNotifyInterceptorRegistrationStrategy&gt;();
...
</pre>
</li>
<p>Код стал короче и понятнее напорядок.</p>
<p>PS. Детали того, как именно это все устроено смотрите тут: <a href="http://innovatian.com/2010/01/ninject-extensions-interception-and-iautonotifypropertychanged-ianpc/" title="http://innovatian.com/2010/01/ninject-extensions-interception-and-iautonotifypropertychanged-ianpc/" target="_blank"></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.kurdyukov.com/2012/01/31/aop-inotifypropertychanged/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>System.BadImageFormatException при загрузке тестов в ReSharper</title>
		<link>http://www.kurdyukov.com/2012/01/24/system-badimageformatexception-tests-resharper/</link>
		<comments>http://www.kurdyukov.com/2012/01/24/system-badimageformatexception-tests-resharper/#comments</comments>
		<pubDate>Mon, 23 Jan 2012 22:31:01 +0000</pubDate>
		<dc:creator>alik</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[ReSharper]]></category>

		<guid isPermaLink="false">http://www.kurdyukov.com/?p=161</guid>
		<description><![CDATA[В начале создания авто-тестов в одном проекте на C# начал возникать System.BadImageFormatException при попытке запуска тестов из ReSharper. Выяснение показало, что проблема была в том, что сборка с тестами имела Any CPU. А тестируемые классы были в EXE, который был собран в x86. При этом Windows используется 64х битный, следовательно Any CPU = x64. Решение [...]]]></description>
			<content:encoded><![CDATA[<p>В начале создания авто-тестов в одном проекте на C# начал возникать System.BadImageFormatException при попытке запуска тестов из ReSharper. Выяснение показало, что проблема была в том, что сборка с тестами имела Any CPU. А тестируемые классы были в EXE, который был собран в x86. При этом Windows используется 64х битный, следовательно Any CPU = x64.</p>
<p>Решение просто &#8211; указать в тестовой сборке целевую платформу x86. Это делается в закладке Build свойств проекта тестовой сборки.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kurdyukov.com/2012/01/24/system-badimageformatexception-tests-resharper/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Названия обработчиков событий в VS2010</title>
		<link>http://www.kurdyukov.com/2012/01/09/vs2010-handy/</link>
		<comments>http://www.kurdyukov.com/2012/01/09/vs2010-handy/#comments</comments>
		<pubDate>Mon, 09 Jan 2012 15:05:36 +0000</pubDate>
		<dc:creator>alik</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[c#]]></category>

		<guid isPermaLink="false">http://www.kurdyukov.com/?p=152</guid>
		<description><![CDATA[После установки ReSharper на Visual Studio 2010 (всем разработчикам на C# рекоммендую, кста) наиболее активно разражает подсвечивание названий методов, который автоматически генерируются Visual Designer для обработки событий, поскольку название типа &#171;Form1_Load&#187; никак не соответствует идеям начинать название с глагола и не использовать &#171;_&#187;. Но это можно исправить. Есть 2 способа исправления проблемы. 1. Изменить способ [...]]]></description>
			<content:encoded><![CDATA[<p>После установки ReSharper на Visual Studio 2010 (всем разработчикам на C# рекоммендую, кста) наиболее активно разражает подсвечивание названий методов, который автоматически генерируются Visual Designer для обработки событий, поскольку название типа &laquo;Form1_Load&raquo; никак не соответствует идеям начинать название с глагола и не использовать &laquo;_&raquo;. Но это можно исправить.<br />
<span id="more-152"></span><br />
Есть 2 способа исправления проблемы.</p>
<p><strong>1. Изменить способ генерации названий методов</strong><br />
<em>Предпочтительный</em><br />
<a href="http://www.kurdyukov.com/wp-content/uploads/2012/01/screenshot.png"><img src="http://www.kurdyukov.com/wp-content/uploads/2012/01/screenshot.png" alt="" title="Настройки" width="250" height="249" class="alignright size-full wp-image-155" /></a><br />
Установить плагин <a href="http://visualstudiogallery.msdn.microsoft.com/14f62cb9-b559-4bad-9388-37da2150e238/?SRC=Home" target="_blank">EventHandler Naming</a>, который позволяет менять политику именования методов-обработчиков. Устанавливать можно прямо из Extension manager. Даже настройки не требует, по умолчанию настроен как <code>On${SiteName}${EventName}</code>, например, <code>OnForm1Load</code>. Если надо, настраивается.</p>
<p><strong>2. Настроить ReSharper, чтобы он не ругался</strong></p>
<ol>
<li>Идем в меню ReSharper | Options | Languages | C# | C# Naming Style</li>
<li>Переключаем на &laquo;Advanced settings&#8230;&raquo;</li>
<li>Меняем значение &laquo;Event subscriptions on fields&raquo; с умолчального <code>$object$_On$event$</code> на <code>$object$_$event$</code></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.kurdyukov.com/2012/01/09/vs2010-handy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Поучимся?</title>
		<link>http://www.kurdyukov.com/2011/09/26/learning/</link>
		<comments>http://www.kurdyukov.com/2011/09/26/learning/#comments</comments>
		<pubDate>Mon, 26 Sep 2011 12:06:08 +0000</pubDate>
		<dc:creator>alik</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[leaning]]></category>
		<category><![CDATA[stanford]]></category>

		<guid isPermaLink="false">http://www.kurdyukov.com/?p=142</guid>
		<description><![CDATA[Я считаю, без каких-то новых знаний жить не особо интересно. Поэтому стараюсь учиться. А тут Стэнфорд предлагает уникальную возможность бесплатно поучиться computer science. Предлагаемые курсы: Класс по машинному обучению Класс по искусственному интеллекту Класс введения в базы данных Все классы бесплатные, будут домашние задания. Стартуют примерно 10 октября. Язык преподавания &#8211; английский. Я сам записался [...]]]></description>
			<content:encoded><![CDATA[<p>Я считаю, без каких-то новых знаний жить не особо интересно. Поэтому стараюсь учиться. А тут Стэнфорд предлагает уникальную возможность бесплатно поучиться computer science.<br />
<span id="more-142"></span><br />
Предлагаемые курсы:</p>
<ul>
<li><a href="http://www.ml-class.org/course/auth/welcome">Класс по машинному обучению</a></li>
<li><a href="http://www.ai-class.com/">Класс по искусственному интеллекту</a></li>
<li><a href="http://www.db-class.org/course/auth/welcome">Класс введения в базы данных</a></li>
</ul>
<p>Все классы бесплатные, будут домашние задания. Стартуют примерно 10 октября. Язык преподавания &#8211; английский.</p>
<p>Я сам записался на машинное обучению и искусственному интеллекту.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kurdyukov.com/2011/09/26/learning/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

