<?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/"
	xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Trainee's Weblog</title>
	<atom:link href="http://gltrainee.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://gltrainee.wordpress.com</link>
	<description>блог .NET разработчиков ... in .Net veritas ...</description>
	<lastBuildDate>Thu, 03 Jul 2008 14:50:21 +0000</lastBuildDate>
	<generator>http://wordpress.com/</generator>
	<language>ru</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<cloud domain='gltrainee.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://www.gravatar.com/blavatar/4849b8cdccdb7cbe479254e464bcb906?s=96&#038;d=http://s.wordpress.com/i/buttonw-com.png</url>
		<title>Trainee's Weblog</title>
		<link>http://gltrainee.wordpress.com</link>
	</image>
			<item>
		<title>Импортирование UDT в MS SQL SERVER 2005</title>
		<link>http://gltrainee.wordpress.com/2008/07/03/%d0%b8%d0%bc%d0%bf%d0%be%d1%80%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-udt-%d0%b2-ms-sql-server-2005/</link>
		<comments>http://gltrainee.wordpress.com/2008/07/03/%d0%b8%d0%bc%d0%bf%d0%be%d1%80%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-udt-%d0%b2-ms-sql-server-2005/#comments</comments>
		<pubDate>Thu, 03 Jul 2008 13:01:52 +0000</pubDate>
		<dc:creator>masalov</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://gltrainee.wordpress.com/?p=43</guid>
		<description><![CDATA[Как вы уже, наверное, знаете, в  состав MS SQL Server 2005 была интегрирована CLR, что сделало возможным разворачивать наши приложения в пределах процесса MS SQL Server.

Данная статья посвящена созданию UDT(user defined type)  и интеграции его в MS SQL Server.
Итак, давайте начнем&#8230; Для начала необходимо рассмотреть требования, предъявляемые к каждому UDT:
- UDT реализуется в [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gltrainee.wordpress.com&blog=3911599&post=43&subd=gltrainee&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Как вы уже, наверное, знаете, в  состав MS SQL Server 2005 была интегрирована CLR, что сделало возможным разворачивать наши приложения в пределах процесса MS SQL Server.</p>
<p><span id="more-43"></span><br />
Данная статья посвящена созданию UDT(user defined type)  и интеграции его в MS SQL Server.</p>
<p>Итак, давайте начнем&#8230; Для начала необходимо рассмотреть требования, предъявляемые к каждому UDT:<br />
- UDT реализуется в виде public структур или классов;</p>
<p>- Должны быть отмечены атрибутом SqlUserDefinedType с указанием обязательных параметров, касающихся способа сериализации, и атрибутом Serializable</p>
<p>- Должны реализовывать интерфейс INullable<br />
public bool IsNull 			Проверка на NULL</p>
<p>- Должны реализовывать методы:<br />
public static &lt;Тип&gt; Parse(SqlString s)	Преобразование из строки<br />
public override string ToString() 		Преобразование в строку<br />
public static &lt;Тип&gt; Null			NULL значение</p>
<p>- Если выбран способ сериализации UserDefined, то должен быть реализован интерфейс IBinarySerialize<br />
public void Write(System.IO.BinaryWriter w)    Сериализация<br />
public void Read(System.IO.BinaryReader r)    Десериализация</p>
<p>Теперь давайте рассмотрим небольшой пример, в котором я реализовал 3 UDP:<br />
1) SQLPoint &#8211; точка, которая представлена в виде 2х значений, разделенными двоеточием &#8211; x и y координаты. Пример: &laquo;4:2&#8243;<br />
2) SQLPointList &#8211; множество точек, разделенными запятыми. Пример: &laquo;2:1,5:3,22:12&#8243;<br />
3) ListOfSQLPointList &#8211; набор множеств точек. Пример: &laquo;{2:4,4:5,2:1},{2:4,4:4},{2:2}&raquo;</p>
<p>Создадим сборку, в которой реализуем данные типы:</p>
<div style="background:#AEAEAE;border:1px;">using System;<br />
using System.Collections.Generic;<br />
using System.Linq;<br />
using System.Text;<br />
using System.Data.SqlTypes;</p>
<p>namespace NewType<br />
{<br />
[Serializable]<br />
[Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute(Microsoft.SqlServer.Server.Format.UserDefined, MaxByteSize = 500)]<br />
public class ListOfSQLPointList : Microsoft.SqlServer.Server.IBinarySerialize, INullable<br />
{<br />
List _lists;</p>
<p>public List Lists<br />
{<br />
get { return _lists; }<br />
set { _lists = value; }<br />
}<br />
public ListOfSQLPointList()<br />
{<br />
_lists = new List();<br />
}</p>
<p>#region IBinarySerialize Members</p>
<p>public void Read(System.IO.BinaryReader r)<br />
{<br />
string strRead = r.ReadString();<br />
ListOfSQLPointList listOfPointLists = ListOfSQLPointList.Parse(strRead);<br />
foreach (SQLPointList pointList in listOfPointLists.Lists)<br />
{<br />
this._lists.Add(pointList);<br />
}</p>
<p>}<br />
public static ListOfSQLPointList Parse(SqlString s)<br />
{<br />
ListOfSQLPointList list = new ListOfSQLPointList();<br />
string[] strArr = s.ToString().Split(new string[] { &laquo;},{&raquo; }, StringSplitOptions.RemoveEmptyEntries);<br />
for (int i = 0; i &lt; strArr.Length; i++)<br />
{<br />
strArr[i] = strArr[i].TrimEnd(&#8216;}&#8217;);<br />
strArr[i] = strArr[i].TrimStart(&#8216;{&#8216;);<br />
SQLPointList point = SQLPointList.Parse(strArr[i]);<br />
list.Lists.Add(point);<br />
}<br />
return list;<br />
}<br />
public override string ToString()<br />
{<br />
string strResult = String.Empty;<br />
if (_lists.Count &gt; 0)<br />
{<br />
for (int i = 0; i &lt; this._lists.Count &#8211; 1; i++)<br />
{<br />
strResult += &laquo;{&raquo; + _lists[i].ToString() + &laquo;},&raquo;;<br />
}</p>
<p>strResult += &laquo;{&raquo; + _lists[_lists.Count - 1].ToString() + &laquo;}&raquo;;<br />
}<br />
return strResult;<br />
}<br />
public void Write(System.IO.BinaryWriter w)<br />
{<br />
w.Write(this.ToString());<br />
}</p>
<p>#endregion</p>
<p>#region INullable Members</p>
<p>public bool IsNull<br />
{<br />
get { return false; }<br />
}</p>
<p>#endregion</p>
<p>public static ListOfSQLPointList Null<br />
{<br />
get { return null; }<br />
}<br />
}</p>
<p>[Serializable]<br />
[Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute(Microsoft.SqlServer.Server.Format.UserDefined, MaxByteSize = 150)]<br />
public class SQLPointList : Microsoft.SqlServer.Server.IBinarySerialize, INullable<br />
{<br />
List _points;</p>
<p>public List Points<br />
{<br />
get { return _points; }<br />
set { _points = value; }<br />
}<br />
public SQLPointList()<br />
{<br />
_points = new List();<br />
}</p>
<p>#region IBinarySerialize Members</p>
<p>public void Read(System.IO.BinaryReader r)<br />
{<br />
string strRead = r.ReadString();<br />
SQLPointList pointList = SQLPointList.Parse(strRead);<br />
foreach (SQLPoint point in pointList.Points)<br />
{<br />
this._points.Add(point);<br />
}</p>
<p>}<br />
public static SQLPointList Parse(SqlString s)<br />
{<br />
SQLPointList list = new SQLPointList();<br />
string[] strArr = s.ToString().Split(&#8216;,&#8217;);<br />
for (int i = 0; i &lt; strArr.Length; i++)<br />
{<br />
if (strArr[i] != &laquo;&raquo;)<br />
{<br />
SQLPoint point = SQLPoint.Parse(strArr[i]);<br />
list.Points.Add(point);<br />
}<br />
}<br />
return list;<br />
}<br />
public override string ToString()<br />
{<br />
string strResult = String.Empty;<br />
if (_points.Count &gt; 0)<br />
{<br />
for (int i = 0; i &lt; _points.Count &#8211; 1; i++)<br />
{<br />
strResult += _points[i].ToString() + &#8216;,&#8217;;<br />
}<br />
strResult += _points[_points.Count - 1].ToString();<br />
}<br />
return strResult;<br />
}<br />
public void Write(System.IO.BinaryWriter w)<br />
{<br />
w.Write(this.ToString());<br />
}</p>
<p>#endregion</p>
<p>#region INullable Members</p>
<p>public bool IsNull<br />
{<br />
get { return false; }<br />
}</p>
<p>#endregion</p>
<p>public static SQLPointList Null<br />
{<br />
get { return null; }<br />
}<br />
}</p>
<p>[Serializable]<br />
[Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute(Microsoft.SqlServer.Server.Format.UserDefined, MaxByteSize = 20)]<br />
public class SQLPoint : Microsoft.SqlServer.Server.IBinarySerialize, INullable<br />
{<br />
private int _x;<br />
private int _y;</p>
<p>public int X<br />
{<br />
get { return _x; }<br />
set { _x = value; }<br />
}<br />
public int Y<br />
{<br />
get { return _y; }<br />
set { _y = value; }<br />
}</p>
<p>#region IBinarySerialize Members</p>
<p>public void Read(System.IO.BinaryReader r)<br />
{<br />
string strResult = r.ReadString();<br />
SQLPoint point = SQLPoint.Parse(strResult);<br />
this._x = point.X;<br />
this._y = point.Y;<br />
}</p>
<p>public void Write(System.IO.BinaryWriter w)<br />
{<br />
w.Write(this.ToString());<br />
}</p>
<p>#endregion</p>
<p>#region INullable Members</p>
<p>public bool IsNull<br />
{<br />
get { return false; }<br />
}</p>
<p>#endregion</p>
<p>public static SQLPoint Parse(SqlString s)<br />
{<br />
string[] strArr = s.ToString().Split(&#8216;:&#8217;);<br />
SQLPoint point = new SQLPoint();<br />
point.X = int.Parse(strArr[0]);<br />
point.Y = int.Parse(strArr[1]);<br />
return point;<br />
}<br />
public override string ToString()<br />
{<br />
return _x.ToString() + &laquo;:&raquo; + _y.ToString();<br />
}<br />
public static SQLPoint Null<br />
{<br />
get { return null; }<br />
}</p>
<p>}<br />
}</p></div>
<p>Открываем Managment Studio, выбираем базу данных, для которой будем импортировать новые типы и создаем SQL запрос</p>
<div style="background:#AEAEAE;border:1px;">CREATE ASSEMBLY NewTypes<br />
FROM &#8216;ПУТЬ К DLL&#8217;ке&#8217; ;<br />
GO<br />
CREATE TYPE SQLPointList<br />
EXTERNAL NAME NewTypes.[NewType.SQLPointList] ;<br />
GO<br />
CREATE TYPE SQLPoint<br />
EXTERNAL NAME NewTypes.[NewType.SQLPoint] ;<br />
go<br />
CREATE TYPE ListOfSQLPointList<br />
EXTERNAL NAME NewTypes.[NewType.ListOfSQLPointList] ;</div>
<p>А также не забудьте активировать CLR в MS SQL SERVER</p>
<div style="background:#AEAEAE;border:1px;">EXEC sp_configure &#8217;show advanced options&#8217; , &#8216;1&#8242;;<br />
go<br />
reconfigure;<br />
go<br />
EXEC sp_configure &#8216;clr enabled&#8217; , &#8216;1&#8242;<br />
go<br />
reconfigure;<br />
&#8211; Turn advanced options back off<br />
EXEC sp_configure &#8217;show advanced options&#8217; , &#8216;1&#8242;;<br />
go</div>
<p>При создании таблицы появится 3 новых типа:<br />
<a href="http://gltrainee.files.wordpress.com/2008/07/111sssss1.jpg"><img class="aligncenter size-full wp-image-45" src="http://gltrainee.files.wordpress.com/2008/07/111sssss1.jpg?w=610&#038;h=349" alt="Sample" width="610" height="349" /></a></p>
<p>И теперь вы сможете сохранять собственный тип в ячейку:<br />
<a href="http://gltrainee.files.wordpress.com/2008/07/111dddd.jpg"><img class="aligncenter size-full wp-image-46" src="http://gltrainee.files.wordpress.com/2008/07/111dddd.jpg?w=605&#038;h=205" alt="" width="605" height="205" /></a></p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/gltrainee.wordpress.com/43/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/gltrainee.wordpress.com/43/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/gltrainee.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/gltrainee.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/gltrainee.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/gltrainee.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/gltrainee.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/gltrainee.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/gltrainee.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/gltrainee.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/gltrainee.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/gltrainee.wordpress.com/43/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gltrainee.wordpress.com&blog=3911599&post=43&subd=gltrainee&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://gltrainee.wordpress.com/2008/07/03/%d0%b8%d0%bc%d0%bf%d0%be%d1%80%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-udt-%d0%b2-ms-sql-server-2005/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/68d963ae477c9c1d15463d3a10c23b56?s=96&#38;d=monsterid" medium="image">
			<media:title type="html">masalov</media:title>
		</media:content>

		<media:content url="http://gltrainee.files.wordpress.com/2008/07/111sssss1.jpg" medium="image">
			<media:title type="html">Sample</media:title>
		</media:content>

		<media:content url="http://gltrainee.files.wordpress.com/2008/07/111dddd.jpg" medium="image" />
	</item>
		<item>
		<title>Новые возможности C# 3.0</title>
		<link>http://gltrainee.wordpress.com/2008/06/26/%d0%bd%d0%be%d0%b2%d1%8b%d0%b5-%d0%b2%d0%be%d0%b7%d0%bc%d0%be%d0%b6%d0%bd%d0%be%d1%81%d1%82%d0%b8-c-30/</link>
		<comments>http://gltrainee.wordpress.com/2008/06/26/%d0%bd%d0%be%d0%b2%d1%8b%d0%b5-%d0%b2%d0%be%d0%b7%d0%bc%d0%be%d0%b6%d0%bd%d0%be%d1%81%d1%82%d0%b8-c-30/#comments</comments>
		<pubDate>Thu, 26 Jun 2008 18:17:56 +0000</pubDate>
		<dc:creator>whitenie</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C# 3.0]]></category>
		<category><![CDATA[ООП]]></category>

		<guid isPermaLink="false">http://gltrainee.wordpress.com/?p=41</guid>
		<description><![CDATA[Впервые, завеса тайны над C# 3.0 и проектом LINQ была приоткрыта примерно полтора года назад, когда создатели и идейные вдохновители этого проекта, Дон Бокс и Андрес Хэйлсберг, выступили на PDC 2005 и поведали миру о том, что же это такое. С тех пор этот проект неоднократно обсуждался как в программистских форумах и блогах, так и [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gltrainee.wordpress.com&blog=3911599&post=41&subd=gltrainee&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Впервые, завеса тайны над C# 3.0 и проектом LINQ была приоткрыта примерно полтора года назад, когда создатели и идейные вдохновители этого проекта, Дон Бокс и Андрес Хэйлсберг, выступили на PDC 2005 и поведали миру о том, что же это такое<span id="more-41"></span>. С тех пор этот проект неоднократно обсуждался как в программистских форумах и блогах, так и на больших конференциях, в том числе и в России – Platform, DevDays, WebDevCon, etc.… Однако время шло, релиза все не случалось, интерес угасал, и проект начал обрастать всяческими слухами, естественно, имеющими мало общего с действительностью, как всяким приличным слухам и положено. В последнее же время, в силу ряда объективных причин – осень, полнолуние, неотвратимая близость релиза C# 3.0, LINQ, следующей версии Фреймворка и студии, разговоры о LINQ и C# 3.0 вспыхнули с новой силой, и со всей очевидностью стало ясно, что ясности в этом вопросе в народе нет. Эта небольшая статья призвана устранить сумбур, восполнить пробел и всячески осветить данный вопрос.… Впрочем, это сверхзадача, первоочередная же задача менее амбициозна – не запутать еще больше…</p>
<p>Тот факт, что .Net Framework не монолитен, а состоит из нескольких компонентов, то есть Common Language Runtime (далее просто «рантайм»), набора библиотек FCL и набора компиляторов – ни для кого не секрет (но многие об этом забывают <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  ).</p>
<p>Теперь же появляется еще одна сущность – LINQ (Language Integrated Query), и данная статья посвящена как раз описанию места, которое занимает LINQ во всей этой кухне, что во что integrated и как этим можно пользоваться&#8230;</p>
<p>Для начала попытаемся сформулировать задачу: для чего вообще вводится LINQ, и какие проблемы с его помощью собираются решать?</p>
<p>На данный момент наиболее распространен объектно-ориентированый подход к разработке. Это достаточно удобная абстракция для большинства практических случаев. Однако она не является панацеей, и далеко не для всех сценариев представляет собой оптимальный выбор. Это хорошо видно на примере баз данных – несмотря на повальное засилье ООП, для персистентных хранилищ данный подход так и не сумел завоевать хоть сколько-нибудь заметную популярность.</p>
<table class="note" border="0" width="98%">
<tbody>
<tr>
<td><strong>ПРИМЕЧАНИЕ</strong><br />
Важное замечание – здесь и далее, когда упоминается ООП, то имеется в виду не ООП вообще, как подход к проектированию, а то, как этот подход выражается в наиболее распространенных современных языках программирования (C++, Java, C#).</td>
</tr>
</tbody>
</table>
<p>Если же попытаться выделить тот класс задач, где ООП перестает справляться &laquo;на отлично&raquo;, то выяснится, что пока мы имеем дело с объектом, как таковым, то все работает замечательно, но как только целый и неделимый объект превращается в контейнер и становится коллекцией других объектов – ситуация заметно осложняется&#8230; Понятное дело, что выразительности ООП достаточно, чтобы не ощущать этот недостаток в полной мере, и, в принципе, с ним мириться…. Но некий дискомфорт все равно присутствует, и особенно остро он ощущается при работе с реляционными источниками данных (там есть и другие проблемы, но они лежат совсем уж за пределами данной темы, однако все вместе это дает эффект перманентного раздражения седалищного нерва). Microsoft предпринял свою попытку вскрыть этот нарыв, на первый взгляд довольно удачную.</p>
<p>Итак, задача формулируется следующим образом: надо добавить в ОО-язык (каковым и является C#) средства работы с коллекциями. Для достижения этой цели было решено перенять положительный опыт реляционных СУБД, которые, по сути, и являются набором коллекций. Одной из основных причин успеха современных РСУБД, использующих SQL, является декларативность языка запросов. Он не требует описывать, «как» достичь результата, а требует лишь указать, «что» надо получить, а «как» – это уже забота оптимизатора и движка самой СУБД. Это позволяет не заботиться о конкретном алгоритме и предоставляет оптимизатору максимум свободы при выборе эффективного решения.</p>
<p>Современные императивные (в том числе и объектно-ориентированные) языки программирования до сих пор не предоставляли декларативных средств обработки данных (подобных SQL). Однако достаточно давно существуют функциональные языки программирования, в которых обработка данных (и особенно списков) достигла высокого уровня и фактически выглядит декларативной. В Microsoft решили взять на вооружение достижения функциональных языков программирования в данной области.</p>
<p>В C# ввели новый декларативный синтаксис и функциональность для работы с коллекциями, но не стали скрывать внутренности механизма реализации этой функциональности, позволяющей данному языку запросов эффективно работать с разными источниками данных. Это, с одной стороны, сделало решение более расширяемым, а с другой – многое из этой функциональности ценно само по себе, вне зависимости от LINQ.</p>
<p>Собственно, дальнейший рассказ о том, что это за новая функциональность, ради чего она сделана именно такой, что из этого получилось, и как это можно использовать.</p>
<h2>Новые возможности C# 3.0<a name="E3B"></a></h2>
<p>Начнем, пожалуй, с конца, уж простите за банальность, так будет проще рассказывать об остальном&#8230; <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>Вывод типа (Type Inference)<a name="EBC"></a></h3>
<p>При объявлении переменных, и особенно при работе с коллекциями (более подробно к этим сценариям мы вернемся позже) , частенько получается громоздкий и избыточный код. Ведь в большинстве случаев переменная имеет такой же тип, что и инициализирующее ее выражение. Стало быть, указание типа переменной только засоряет код и отнимает время. Для облегчения жизни в подобных случаях в C# 3.0 введена такая функциональность, как «вывод типов» (type inference). Суть этого дела довольно проста – если компилятор может вычислить тип из правой части выражения, то декларировать его в левой части не обязательно. Дабы не углубляться в излишний формализм, прибегнем к примеру:</p>
<div id="EGC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="COMMENT">// Вместо того, чтобы писать </span>
MyLongFooClassWithTemplate&lt;MyLongTypeParameter&gt; local
= <span class="KEYWORD">new</span> MyLongFooClassWithTemplate&lt;MyLongTypeParameter&gt;();

<span class="COMMENT">// Можно объявить переменную так:</span>
<span class="KEYWORD">var</span> localVar = <span class="KEYWORD">new</span> MyLongFooClassWithTemplate&lt;MyLongTypeParameter&gt;();

<span class="COMMENT">// А можно даже и так:</span>
<span class="KEYWORD">var</span> i = 1;
<span class="KEYWORD">var</span> s = <span class="STRING">"SomeString"</span>;
<span class="KEYWORD">var</span> z = i + i * i;
<span class="KEYWORD">var</span> c = 'c';

Console.WriteLine(i.GetType()); <span class="COMMENT">// System.Int32</span>
Console.WriteLine(s.GetType()); <span class="COMMENT">// System.String</span>
Console.WriteLine(c.GetType()); <span class="COMMENT">// System.Char</span>
Console.WriteLine(z.GetType()); <span class="COMMENT">// System.Int32</span></pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Ключевое слово «var» вместо типа переменной говорит компилятору о том, что тип выражения надо вычислить из правой части. Обратите внимание – именно компилятору, то есть тип вычисляется не во время выполнения кода, а на этапе компиляции. Язык по прежнему статически типизирован, и все ошибки, связанные с неправильным использованием типов, будут отловлены на этапе компиляции.</p>
<table class="note" border="0" width="98%">
<tbody>
<tr>
<td><strong>ПРИМЕЧАНИЕ</strong><br />
Ключевое слово «var», по всей видимости, использовано потому, что переменная, объявленная с его помощью, может быть изменена в дальнейшем. К сожалению, ключевое слово «var» вызывает ассоциации с динамически типизированными языками. В некоторых функциональных языках используются ключевые слова «let» или «def», но они используются для объявления переменных, доступных только для чтения (характерных для функциональных языков). Ну да не важно, главное не путаться и помнить, что объявленная таки образом переменная получает тип во время компиляции. <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </td>
</tr>
</tbody>
</table>
<p>На самом деле, можно считать, что выведение типов есть и в C# 2.0. Если помните, в случае обобщенного метода тип можно не указывать, он вычисляется из параметра, например так:</p>
<div id="EPD">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="COMMENT">// Если у нас есть такой метод, занимающийся выводом типа на консоль</span>
<span class="KEYWORD">public</span> <span class="KEYWORD">static</span> <span class="KEYWORD">void</span> Print&lt;T&gt;(T variable)
{
  Console.WriteLine(variable.GetType());
}

<span class="COMMENT">// то использовать его можно так:</span>
<span class="COMMENT">// (обратите внимание, явно тип параметра нигде не указывается)</span>
Print(i); <span class="COMMENT">// System.Int32</span>
Print(s); <span class="COMMENT">// System.String</span></pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Но это уж очень урезанная версия данной конструкции.</p>
<p>Как можно заметить, в C# 3 эту функциональность несколько расширили, однако использовать ее можно только в локальных переменных. Скажем, с членами класса такой фокус уже не сработает.</p>
<p>Справедливости ради надо сказать, что в функциональных языках, из которых данный механизм был позаимствован, он используется давно, с удовольствием и гораздо шире, чем будет предложено в третьей версии С#. Строго говоря, даже в статически типизированных языках в большинстве случаев можно обойтись без объявления типа переменной – компилятору известно о типах гораздо больше, чем кажется на первый взгляд, и вывести тип выражения он может в самых причудливых случаях. Но обычно разработчика все же заставляют декларировать тип переменной, это нужно для контроля и облегчения дальнейшей поддержки, код с явно объявленным типом гораздо проще сопровождать.</p>
<p>C# – это первый широко используемый язык общего назначения, где подобная функциональность вводится в достаточно большом объеме. В данном случае разработчики языка пытаются соблюсти баланс между удобством при написании приложения и простотой поддержки кода.</p>
<p>И если на первый взгляд возможность показалась незначительной, то надеюсь, весь ее потенциал раскроется из дальнейших пояснений. К ней еще не раз придется вернуться, и именно поэтому я начал рассказ о новых возможностях языка именно отсюда.</p>
<h3>Анонимные типы (Anonymous Type).<a name="ENE"></a></h3>
<p>Пришло время обсудить одну из ситуаций, когда неудобно декларировать тип переменной при ее объявлении. При полноценной работе с коллекциями тип результата операции или набора операций над коллекциями может сильно отличаться от типов обрабатываемых коллекций. Данный факт порождает следующую проблему&#8230; В господствующих статически типизированных языках (таких, как C++, C#, Java) мы обязаны сначала описать тип данных, а потом уже использовать переменные этого типа. Таким образом, при классическом подходе у нас есть два пути.</p>
<p>Во-первых, можно создавать новый тип каждый раз, когда необходимо выполнить преобразование&#8230; Но в предельном случае каждая операция с коллекцией может порождать новый тип, и есть опасность, что просто не хватит фантазии на имена, а даже если и хватит, радости немного&#8230;</p>
<p>Во-вторых, можно создать один большой тип со всеми полями, которые только могут получиться в результате операций&#8230; Но это тоже не выход, так как данный тип будет постоянно проинициализирован лишь частично, что, по сути, означает отказ от статической типизации – если мы попытаемся обратиться не к тому полю, то ошибка всплывет только во время выполнения. Частным случаем такого подхода являются DataSet-ы, однако их нельзя назвать удачным решением проблемы.</p>
<p>Чтобы выйти из этой ситуации, ввели такое понятие, как «анонимные типы» (anonymous type). Анонимные типы – это возможность создать новый тип, декларируя его не заранее, а непосредственно при создании переменной, причем типы и имена полей выводятся компилятором автоматически из инициализации.</p>
<p>Но, опять-таки, ближе к делу, на примере оно всяко понятнее:</p>
<div id="E1E">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="COMMENT">// Вот так выглядит объявление нового типа:</span>
<span class="KEYWORD">var</span> anon = <span class="KEYWORD">new</span> { a = 3, b = 4.81, c = <span class="STRING">"string data"</span> };

<span class="COMMENT">// дальше можно спокойно использовать</span>
Console.WriteLine(<span class="STRING">“a = “ </span>+ anon.a + <span class="STRING">“\tb = “</span> + anon.b + <span class="STRING">“\tc = ”</span> anon.c);

<span class="COMMENT">// а так можно посмотреть, что же создалось:</span>
Console.WriteLine(anon.GetType());</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>У созданного подобным образом типа нет имени, потому он, собственно, и анонимный, и различается только по сигнатуре входящих в него полей, что хорошо видно при попытке означенное имя запросить.</p>
<p>Как легко можно заметить, здесь также не обошлось без функциональности, описанной в предыдущем разделе. Причем вывод типов помог здесь аж два раза. Во-первых, при объявлении переменной. Без этого нам пришлось бы описывать тип дважды, и все удовольствие от анонимности типа нивелировалось бы утомительностью его объявления. А во-вторых, при описании полей их тип нигде не указан и вычисляется из типа инициализирующего выражения.</p>
<p>К сожалению, у анонимного типа есть один досадный недостаток, серьезно ограничивающий возможности его использования. Его нельзя экспортировать за пределы метода, в котором его создали. Связано это с тем, что при выходе третьей версии C# рантайм не будет изменен – будет использован все тот же рантайм, что поставлялся с .Net Framework 2.0, а в нем не были предусмотрены анонимные типы. Эта непредусмотрительность выливается в то, что невозможно разрешить конфликт имен при экспорте анонимного типа с совпадающей сигнатурой. По этой причине анонимный тип нельзя сделать видимым за пределами сборки. Ограниченность же пределами метода объясняется тем, что если разрешить экспортировать анонимный тип за пределы метода, то протащить его через метод за пределы сборки труда не составит (в принципе, можно было бы запретить использовать эти типы в публичных методах, так как остальные не могут быть видны за пределами сборки – прим.ред.).</p>
<p>Здесь также сложно удержаться от аналогий с функциональными языками. В них присутствует конструкция под названием кортеж (tuple), и служит она примерно для того же самого. Поскольку в функциональных языках, что очевидно из названия, все вертится вокруг функций, им жизненно необходимо иметь возможность возвращать из функции несколько значений. И опять-таки, чтобы не объявлять заранее тип, по полям которого можно было бы распихать выходные параметры, ребята ввели такую штуку как кортеж.</p>
<p>Таким образом, технология анонимных типов в принципе отработана, но есть существенное отличие от кортежей. В ФЯ поля в кортежах не именованы, то есть добраться до значения поля в кортеже можно только с помощью специальных синтаксических форм или по индексу (исключением в данном случае является SQL, результат SQL-запроса как раз представляет собой именованный кортеж). Это не является недостатком именно кортежей, так как в типичных сценариях их использования это проблем не вызывает. Но поскольку создатели C# держали в голове, что одним из основных сценариев использования анонимных типов будет работа с коллекциями, то они совершенно сознательно сделали поля анонимных типов именованными. К именованным полям можно обращаться напрямую (без дополнительной декомпозиции), что удобно в повседневной жизни. Учитывая, что имена полей обычно выводятся компилятором автоматически, код получается кратким и понятным.</p>
<p>Я уделил этому так много внимания потому, что если бы анонимные типы были не именованными, то уже сейчас, даже при текущей версии рантайма, их можно было бы использовать за пределами сборки (что с успехом и делают функциональные языки для .Net, например F#). Но с учетом ориентированности новой функциональности именно на работу с коллекциями, ввод вместо кортежей полноценного типа, пусть и с ограниченной областью видимости, кажется более правильным решением.</p>
<h3>Расширяющие методы (Extension Methods)<a name="E3F"></a></h3>
<p>Следующим этапом работы с коллекциями будет создание набора операторов, необходимых для типичных преобразований&#8230; Или не типичных. Собственно, задача сводится к тому, чтобы дать возможность произвести некую операцию над уже готовым объектом, при этом исходный код объекта, возможно, уже не доступен. В принципе, задача не байт весть какая сложная&#8230; В предыдущих версиях C#, как и в других ОО–языках, она решалась следующим образом – создавался утилитный класс, в котором определялся метод, выполняющий необходимую операцию, и этот метод в качестве параметра принимал на вход наш объект.</p>
<p>Проще объяснить на примере. Допустим, нам хочется, чтобы был утилитный класс, один из методов которого умел бы считать количество элементов в массиве. Тогда мы могли бы создать примерно такой класс:</p>
<div id="EDG">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="KEYWORD">public</span> <span class="KEYWORD">static</span> <span class="KEYWORD">class</span> Util
{
  <span class="KEYWORD">public</span> <span class="KEYWORD">static</span> <span class="KEYWORD">int</span> ElementCount(IEnumerable enumerable)
  {
    <span class="KEYWORD">int</span> i = 0;
    <span class="KEYWORD">foreach</span> (<span class="KEYWORD">var</span> e <span class="KEYWORD">in</span> enumerable)
      i++;
    <span class="KEYWORD">return</span> i;
  }
}

<span class="COMMENT">// И тогда, для любого массива</span>
IEnumerable&lt;<span class="KEYWORD">int</span>&gt; array = <span class="KEYWORD">new</span> <span class="KEYWORD">int</span>[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

<span class="COMMENT">// Можно было бы посчитать количество элементов</span>
Console.WriteLine(Util.ElementCount(array)); <span class="COMMENT">// 10</span></pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Но тут есть пара мелких неудобств. Во-первых, чтобы использовать класс Util и его методы, надо знать, что он есть, по массиву-то никак не вычислишь, что существует Util с таким замечательным методом. А во-вторых, если нам понадобится передать в утилитный метод какие-нибудь параметры, да еще совершить несколько операций подряд, то синтаксис этого дела будет довольно страшненьким. Если нужно использовать несколько утилитных методов одновременно, становится сложно не заблудиться в лесу скобок. Необходимость предварять имена статических методов именами классов, в которых они объявлены, еще больше усугубляет ситуацию. Сравните две следующие строчки:</p>
<div id="EKH">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre>Util.f1(Util.f2(Util.f3(x, y))))
f3(x, y).f2().f1()</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Выход придумали следующий (точнее, позаимствовали из следующего стандарта C++, который так, похоже, и не появится на свет до выхода C# 3.0 – прим.ред.) – достаточно изменить одну строчку кода в утилитном классе:</p>
<div id="EOH">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="COMMENT">// добавить this перед первым параметром метода</span>
<span class="KEYWORD">public</span> <span class="KEYWORD">static</span> <span class="KEYWORD">int</span> ElementCount(<span class="ACCENT">this</span> IEnumerable enumerable)
...
<span class="COMMENT">// и вызывать этот утилитный метод можно так </span>
<span class="KEYWORD">int</span> count = <span class="ACCENT">array</span>.ElementCount();</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Метод, помеченный this, было решено назвать расширяющим методом (extension method).</p>
<p>Работает этот механизм следующим образом. Увидев вызов метода объекта, компилятор сначала проверяет, есть ли необходимый метод у класса этого объекта, и если он отсутствует, пытается найти расширяющий метод. При компиляции расширяющего метода компилятор помечает этот метод специальным атрибутом. В дальнейшем, просматривая список открытых пространств имен, компилятор ищет статические классы, и, если находит, анализирует их на наличие расширяющих методов.</p>
<p>Введением расширяющих методов удалось достичь следующего: во-первых, мы избавились от необходимости явно писать имя утилитного класса. Во-вторых, подобный синтаксис гораздо прозрачнее, если придется записывать несколько операций подряд. В-третьих, автодополнение в Visual Studio само подскажет о наличии подобных методов расширения. Ну и наконец, в четвертых, чтобы это заработало, необходимо, чтобы утилитный класс был объявлен как static, и его методы также были static (что, в общем, логично), таким образом, это провоцирует писать более чистый код – утилитный класс будет именно утилитным и ничем другим (впрочем, это спорное утверждение; многие не находят ничего зазорного в том, чтобы объявлять расширяющие методы в любых, а не только статических, классах – прим.ред.).</p>
<table class="tip" border="0" width="98%">
<tbody>
<tr>
<td><strong>СОВЕТ</strong><br />
При этом добавление this не отменяет старого способа обращения к утилитному методу, его вполне можно вызвать как раньше: int count = Util.ElementCount(array);</td>
</tr>
</tbody>
</table>
<p>Однако надо понимать, что эта функциональность – синтаксический сахар в чистом виде, просто удобная форма вызова утилитных методов и никаких чудес здесь не происходит.</p>
<h3>Лямбда-выражения (Lambda Expression).<a name="EPAAC"></a></h3>
<p>Итак, картина потихоньку начинает вырисовываться. Теперь у нас есть возможность строить примерно такие выражения:</p>
<div id="EUAAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="COMMENT">// псевдокод</span>
<span class="KEYWORD">var</span> result = CollectionA.Join(CollectionB, &lt;условие объединения&gt;).GroupBy(&lt;условие группировки&gt;).Where(&lt;условие фильтрации&gt;).Select(&lt;описание нового типа&gt;);</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Но остается неясным вопрос с различными условиями и предикатами – как их передавать в выражение? Очевидно, должна существовать некая функция, которая выполняет проверку этих условий, и у нас должна быть возможность эту функцию в выражение подпихнуть.</p>
<p>Тут опять будет уместно сделать небольшое лирическое отступление в сторону функциональных языков. Для программирования в функциональном стиле необходимо, чтобы язык поддерживал работу с функциями как первоклассными значениями (first-class functions). На практике это означает соблюдение следующих условий:</p>
<ul style="list-style-type:square;list-style-image:none;list-style-position:outside;">
<li>Функция может быть определена в любом месте.</li>
<li>Функцию можно передать в качестве параметра в другую функцию.</li>
<li>Функцию можно вернуть в качестве параметра из другой функции.</li>
<li>Можно производить вычисления над функциями, получая новые функции.</li>
</ul>
<p>В C# версии 1.0 не поддерживались подобного рода конструкции. Пытливому уму должно быть очевидно, что делегаты в принципе подходят на роль функций первого класса, но в первой версии C# их нельзя было объявить в произвольном месте. Скажем, внутри метода сделать этого не удалось бы.</p>
<p>Давайте в очередной раз прибегнем к практической иллюстрации. Допустим, нам захотелось отфильтровать коллекцию значений типа int таким образом, чтобы остались только четные числа.</p>
<div id="ENBAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="COMMENT">// для начала опишем ExtensionMethod для фильтрации</span>
<span class="KEYWORD">public</span> <span class="KEYWORD">static</span> IEnumerable Filter&lt;T&gt;(
  <span class="KEYWORD">this</span> IEnumerable&lt;T&gt; enumerable,
  ConditionDelegate&lt;T&gt; condition)
{
  <span class="KEYWORD">foreach</span> (T e <span class="KEYWORD">in</span> enumerable)
    <span class="KEYWORD">if</span> (condition(e))
      <span class="KEYWORD">yield</span> <span class="KEYWORD">return</span> e;
} 

<span class="COMMENT">// Естественно, где-то должен быть описан и ConditionDelegate</span>
<span class="KEYWORD">public</span> <span class="KEYWORD">delegate</span> <span class="KEYWORD">bool</span> ConditionDelegate&lt;T&gt;(T condition);</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Если бы мы попытались реализовать механизм работы с коллекциями с помощью обычных методов, то пришлось бы писать примерно так:</p>
<div id="EMCAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="COMMENT">// сначала где-то реализовать тело метода</span>
<span class="KEYWORD">public</span> <span class="KEYWORD">static</span> <span class="KEYWORD">bool</span> <span class="ACCENT">IsEven</span>(<span class="KEYWORD">int</span> n)
{
  <span class="KEYWORD">return</span> n % 2 == 0;
}

<span class="COMMENT">// Ну а потом произвести непосредственно фильтрацию, передав ссылку на метод,
// запакованный в делегат, в качестве параметра.</span>
<span class="KEYWORD">foreach</span> (<span class="KEYWORD">var</span> e <span class="KEYWORD">in</span> array.Filter(<span class="KEYWORD">new</span> ConditionDelegate&lt;<span class="KEYWORD">int</span>&gt;(IsEven)))
  Console.Write(e + <span class="STRING">", "</span>);</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>В некоторых случаях это даже удобно (если нужно использовать одно и то же условие в нескольких местах), но на практике такие методы используются по большей части только один раз, и объявлять их намного удобнее «по месту». По этой причине уже во второй версии C# ввели такую конструкцию, как «анонимный метод». Анонимный метод уже полностью удовлетворяет определению первоклассной функции, так как может быть определен в любом месте, в том числе и в теле метода. Таким образом, вышеприведенный код фильтрации с использованием анонимных методов может трансформироваться в следующее:</p>
<div id="ENDAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="KEYWORD">foreach</span> (<span class="KEYWORD">var</span> e <span class="KEYWORD">in</span> array.Filter(
  <span class="KEYWORD">delegate</span>(<span class="KEYWORD">int</span> n) { <span class="KEYWORD">return</span> n % 2 == 0; }))
Console.Write(e + <span class="STRING">", "</span>);</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Очевидно, здесь уже не нужно объявлять заранее метод IsEven из предыдущего примера, так как его тело определено прямо в месте использования.</p>
<table class="tip" border="0" width="98%">
<tbody>
<tr>
<td><strong>СОВЕТ</strong><br />
Обратите внимание: здесь мне не пришлось указывать тип параметра делегата при обращении к утилитному методу – вместо Filter&lt;int&gt;(…) используется Filter(…). Здесь нам опять приходит на помощь вывод типов.</td>
</tr>
</tbody>
</table>
<p>Конечно, удобно описывать метод (анонимный) в месте использования, но кратким синтаксис анонимных методов не назовешь, и запрос, условия в котором задаются с их помощью, может получиться весьма длинным и плохо читаемым&#8230; Поэтому в C# 3.0 было решено свести синтаксис анонимных методов к минимуму. Лишними оказались ключевое слово «delegate», указание типа параметра (опять спасибо вычислению типов), фигурные скобки (если у анонимного метода имеется всего один параметр) и слово «return» (подразумевается, что если return нет, то функция состоит из одного выражения, результат которого и является возвращаемым результатом функции), а для отделения параметра от тела метода ввели оператор =&gt;. Результат было решено назвать лямбда-выражением (Lambda Expression).</p>
<table class="note" border="0" width="98%">
<tbody>
<tr>
<td><strong>ПРИМЕЧАНИЕ</strong><br />
Слово «лямбда» позаимствовано из функциональных языков, берущих свое начало из лямбда-исчислений Черча (см. http://ru.wikipedia.org/wiki/Лямбда-исчисление). Еще самый первый функциональный язык, Lisp, основывался на лямбдах.</td>
</tr>
</tbody>
</table>
<p>С применением вышеописанного синтаксиса вызов метода фильтрации будет выглядеть так:</p>
<div id="EMEAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="KEYWORD">foreach</span> (<span class="KEYWORD">var</span> e <span class="KEYWORD">in</span> array.Filter(n =&gt; n % 2 == 0))
  Console.Write(e + <span class="STRING">", "</span>);</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>То есть объявление анонимного метода:</p>
<div id="EZEAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="KEYWORD">delegate</span>(<span class="KEYWORD">int</span> n) { <span class="KEYWORD">return</span> n % 2 == 0; }</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>сократилось до:</p>
<div id="EEFAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre>n =&gt; n % 2 == 0</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Естественно, применение лямбда-выражений не ограничивается передачей условий в функцию. Мы вполне можем использовать их следующим образом:</p>
<div id="EIFAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre>ConditionDelegate&lt;<span class="KEYWORD">int</span>&gt; isEven = n =&gt; n % 2 == ;
Console.WriteLine(isEven(2));</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>С помощью описанной выше функциональности уже можно реализовать довольно удобный механизм для работы с различного рода контейнерами и коллекциями. Вместе с C# 3.0 будет поставляться несколько библиотек с набором расширяющих методов и делегатов, где все это уже реализовано для любого типа, реализующего интерфейс IEnumerable. Таким образом, любой объект, реализующий IEnumerable, автоматически может участвовать в запросе.</p>
<p>Скажем, подсчитать количество четных элементов в вышеприведенном массиве можно будет примерно так:</p>
<div id="ERFAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="KEYWORD">var</span> q = array.Where(n =&gt; n % 2 == 0).Count();</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>или так:</p>
<div id="EYFAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="KEYWORD">var</span> q = array.Count(n =&gt; n % 2 == 0);</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Но на самом деле это только полдела.</p>
<h3>Вывод типов и лямбда-выражения<a name="EAGAC"></a></h3>
<p>Здесь нужно сделать небольшое лирическое отступление с пояснением. Дело в том, что замечательная функциональность вывода типов работает со всеми типами переменных, кроме анонимных методов и лямбд. То есть нельзя написать вот так:</p>
<div id="EFGAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="KEYWORD">var</span> func = n =&gt; n % 2 == 0;</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Может показаться, что проблема состоит в том, что компилятор не может вывести тип функции. Но это не так. Используемые в теле функции константы однозначно говорят компилятору о типе параметра. Но, допустим, у нас определены следующие делегаты:</p>
<div id="EMGAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="KEYWORD">public</span> <span class="KEYWORD">delegate</span> <span class="KEYWORD">bool</span> Predicate1(<span class="KEYWORD">int</span> n);
<span class="KEYWORD">public</span> <span class="KEYWORD">delegate</span> <span class="KEYWORD">bool</span> Predicate2(<span class="KEYWORD">int</span> n);
<span class="KEYWORD">public</span> <span class="KEYWORD">delegate</span> <span class="KEYWORD">bool</span> Predicate3&lt;T&gt;(T n);
<span class="KEYWORD">public</span> <span class="KEYWORD">delegate</span> R Predicate4&lt;T, R&gt;(T n);</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Как компилятор догадается, какому из этих делегатов соответствует наша лямбда, сигнатуры ведь совпадают? Да никак. Собственно, в этом и проблема.</p>
<p>Все бы ничего – в принципе, объявить тип делегата слева – не проблема. Но ведь одна из основных причин введения в язык явного механизма вывода типов – удобство работы с анонимными типами, их-то нет ни какого смысла слева объявлять&#8230; Если наша гипотетическая лямбда должна вернуть не bool, а анонимный тип, как ее описать?</p>
<p>Допустим, есть такой делегат:</p>
<div id="EPHAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="KEYWORD">public</span> <span class="KEYWORD">delegate</span> R Func&lt;T, R&gt;(T t); <span class="COMMENT">// а он на самом деле примерно такой
</span><span class="KEYWORD">                                   //</span><span class="COMMENT"> и есть в поставке библиотеки...:)</span></pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>и нужно описать операцию проекции, делающую из объекта «пользователь» урезанную версию, которая содержит только имя, логин и e-mail. Иными словами, надо как-то объявить такую лямбду:</p>
<div id="E3HAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre>... = u =&gt; <span class="KEYWORD">new </span>{ u.Name, u.Login, u.EMail };</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>По описанным выше причинам именно так, в лоб, сделать не получится, но есть тайный ход&#8230;</p>
<p>Суть обходного маневра заключается в объявлении дополнительной функции, задача которой – рассказать компилятору, что за делегат мы хотим использовать. Итак, вводим метод:</p>
<div id="EFIAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="KEYWORD">public</span> Func&lt;T, R&gt; MakeLambda&lt;T, R&gt;(Func&lt;T, R&gt; f, T t){ <span class="KEYWORD">return</span> f; }</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Как видно, метод – совершенно абстрактный, и ничего конкретного не делает. Практически он просто возвращает переданную в него функцию (делегат). Но он возвращает совершенно конкретный делегат, и этого уже достаточно компилятору, чтобы вычислить тип лямбды. Значит можно сделать примерно такой вызов:</p>
<div id="EOIAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="KEYWORD">var</span> userProjector = MakeLambda((User u) =&gt; <span class="KEYWORD">new </span>{ u.Name, u.Login, u.EMail });
<span class="KEYWORD">var</span> limitedEdition = userProjector(u);</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Что, собственно, и требовалось получить. <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>Дерево выражений (Expression Tree)<a name="E1IAC"></a></h3>
<p>Описанный выше способ позволяет указать, «что» нам надо, однако должен существовать некий механизм, который возьмет в одну лапу «что», а в другую имеющийся набор коллекций, и поймет, «как» это делать. В случае коллекций в памяти эту роль брал на себя компилятор C#, а собственно алгоритм того, «как», описывался в соответствующих лямбда-выражениях и расширяющих методах. Но для других источников данных представление нашего «что» в виде байт-кода не очень удобно&#8230; Выход придумали следующий – ввели специальный тип Expression&lt;T&gt;, экземпляру которого можно присвоить лямбда-выражение. При компиляции тело лямбды не компилируется, а сохраняется в виде данных, представляющих собой Абстрактное Синтаксическое Дерево – AST (Abstract Syntactic Tree) – вышеупомянутой лямбды.</p>
<p>Выглядит это примерно так:</p>
<div id="EBJAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="COMMENT">// Обычная лямбда</span>
Predicate&lt;<span class="KEYWORD">int</span>&gt; isEven = n =&gt; n % 2 == 0;
Console.WriteLine(isEven); <span class="COMMENT">// System.Predicate`1[System.Int32]</span>

<span class="COMMENT">// Expression </span>
Expression&lt;Predicate&lt;<span class="KEYWORD">int</span>&gt;&gt; exIsEven = n =&gt; n % 2 == 0;
Console.WriteLine(exIsEven); <span class="COMMENT">// n =&gt; ((n % 2) = 0)</span>

Console.WriteLine(isEven(2));   <span class="COMMENT">// true</span>
Console.WriteLine(exIsEven(2)); <span class="COMMENT">// Compilation error</span></pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Такой подход позволяет в ходе компиляции или выполнения разобрать любым другим интерпретатором полученное AST и реализовать запрос к определенным данным. Именно по такому принципу и работают различные реализации LINQ, например, LINQ 2 SQL и LINQ 2 XML.</p>
<p>Для удобства работы с AST Expression предоставляет довольно богатый API – набор методов, с помощью которых переданный участок кода можно как разобрать, так и «собрать», и даже скомпилировать в байт-код для последующего выполнения. Выглядит это примерно так:</p>
<div id="EYJAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="COMMENT">// тело лямбды
//
</span>Console.WriteLine(exIsEven.Body); <span class="COMMENT">// ((n % 2)=0

// тип лямбды
</span>Console.WriteLine(exIsEven.Type); <span class="COMMENT">// System.Predicate`1[System.Int32]

// имя параметра
</span>Console.WriteLine(exIsEven.Parameters[0]); <span class="COMMENT">// n</span></pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Новое выражение можно построить и динамически:</p>
<div id="EFKAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="COMMENT">// создать параметр лямбды</span>
<span class="KEYWORD">var</span> parameterN = Expression.Parameter(<span class="KEYWORD">typeof</span>(<span class="KEYWORD">int</span>), <span class="STRING">"n"</span>);

<span class="COMMENT">//  собственно построение выражения</span>
<span class="COMMENT">// </span>
<span class="KEYWORD">var</span> expression = Expression.Lambda&lt;Predicate&lt;<span class="KEYWORD">int</span>&gt;&gt;(
  Expression.Equal(
    Expression.Modulo(
    parameterN,
    Expression.Constant(2)),
    Expression.Constant(0)
  ),
  parameterN);

<span class="COMMENT">// выводим, что получилось</span>
Console.WriteLine(expression); <span class="COMMENT">// n =&gt; ((n % 2) =0)</span>

<span class="COMMENT">// теперь это можно скомпилировать</span>
Predicate&lt;<span class="KEYWORD">int</span>&gt; compiledExpression = expression.Compile();

<span class="COMMENT">// и использовать</span>
Console.WriteLine();
Console.WriteLine(<span class="STRING">" 2 is Even ? "</span> + compiledExpression(2)); <span class="COMMENT">// true</span>
Console.WriteLine(<span class="STRING">" 3 is Even ? "</span> + compiledExpression(3)); <span class="COMMENT">// false</span></pre>
</td>
</tr>
</tbody>
</table>
</div>
<h3>Ленивые вычисления (Lazy Evaluation)<a name="ENLAC"></a></h3>
<p>Суть явления под названием «ленивые вычисления» заключается в том, что вычисления откладываются до тех пор, пока не понадобится их результат. Такой подход позволяет гарантировать, что вычисляться будут только те данные, которые требуются для получения конечного результата, и тем самым позволяет описывать только зависимости функций друг от друга, и не следить за тем, чтобы не осуществлялось «лишних вычислений».</p>
<table class="note" border="0" width="98%">
<tbody>
<tr>
<td><strong>ПРИМЕЧАНИЕ</strong><br />
В исходном своем смысле «ленивые вычисления» подразумевали откладывание вычислений до того момента, пока их результат не понадобится программе. При этом, если программа однажды затребовала вычисляемое значение, то значение повторно не вычисляется. Итераторы C# же, используемые в LINQ, производят вычисления при каждом новом запросе данных. Поэтому называть их «ленивыми вычислениями» не вполне корректно, но, в общем, это несущественно. – прим.ред.</td>
</tr>
</tbody>
</table>
<p>В случае C# это может быть проиллюстрировано следующим образом:</p>
<div id="EYLAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="COMMENT">// используя несколько видоизмененный класс с расширяющим </span>
<span class="COMMENT">// методом из предыдущего примера</span>
<span class="KEYWORD">public</span> <span class="KEYWORD">static</span> <span class="KEYWORD">class</span> Util
{

  <span class="KEYWORD">public</span> <span class="KEYWORD">static</span> IEnumerable&lt;T&gt; LazyFilter&lt;T&gt;(
    <span class="KEYWORD">this</span> IEnumerable&lt;T&gt; enumerable,
    Predicate&lt;T&gt; predicate)
  {
    <span class="KEYWORD">foreach</span> (<span class="KEYWORD">var</span> e <span class="KEYWORD">in</span> enumerable)
      <span class="KEYWORD">if</span> (predicate(e))
      {
        Console.Write(<span class="STRING">"(true)"</span>);
        <span class="KEYWORD">yield</span> <span class="KEYWORD">return</span> e;
      }
  }
}

<span class="COMMENT">// следующий код
</span>IEnumerable&lt;<span class="KEYWORD">int</span>&gt; array = <span class="KEYWORD">new</span> [] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

Console.WriteLine(<span class="STRING">"фильтр"</span>);
<span class="KEYWORD">var</span> q = array.LazyFilter(n =&gt; n % 2 == 0);
Console.WriteLine(<span class="STRING">"итератор"</span>);
<span class="KEYWORD">foreach</span> (<span class="KEYWORD">var</span> v <span class="KEYWORD">in</span> q)
  Console.Write(v + <span class="STRING">", "</span>);

<span class="COMMENT">// выдаст такой результат:
</span><span class="STRING">фильтр
итератор
(true)2, (true)4, (true)6, (true)8, (true)10,</span></pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>То есть, реальное обращение к элементам коллекции array произошло не в тот момент, когда была применена фильтрация и объявлена переменная «q», а когда нам понадобился результат этой фильтрации. Причина такого поведения в реализации утилитного метода LazyFilter&lt;T&gt;. Если бы он был описан не через yield return, а прямым перебором, то фильтрация произошла бы в момент использования.</p>
<p>Все стандартные расширяющие методы из библиотек LINQ, реализованы именно по принципу ленивых вычислений. Сделано это для того, чтобы была возможность применять несколько последовательных операций в разных выражениях, прежде чем реально будет выполнен запрос.</p>
<p>Например, так:</p>
<div id="EWNAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="KEYWORD">var</span> q = array.Where(...); <span class="COMMENT">// запрос не выполняется
</span>
<span class="COMMENT">// вычисления</span>
<span class="COMMENT">// ...</span>
q = q.Where(...); <span class="COMMENT">// и здесь не выполняется</span>
q = q.Select(...).Where(...); <span class="COMMENT">// и даже здесь</span>

<span class="COMMENT">// а вот здесь уже будет реальное выполнение запроса</span>
<span class="KEYWORD">foreach</span>(<span class="KEYWORD">var</span> result <span class="KEYWORD">in</span> q)
...</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Остались завершающие штрихи и мелкие приятности&#8230;</p>
<h3>Auto Properties<a name="EQOAC"></a></h3>
<p>Мы все прекрасно знаем правила гигиены при написании кошерного кода. Одно из них заключается в том, что в классе не должно быть публичных полей. Вместо них должно быть приватное поле, обернутое в свойство. Все бы ничего, но если ваш класс состоит практически из одних публичных свойств (а такое встречается довольно часто), то выглядит это довольно забавно, но ни разу не практично. Если написать подобный класс сильно помогают различного рода механизмы автодополнения, типа того же ReSharper-а, то прочитать это дело – задача нетривиальная&#8230;</p>
<p>Выход придумали изящный и простой. Если публичное свойство является всего лишь оберткой над приватной переменной и никакой логики не содержит, то достаточно задекларировать его точно таким же образом, как это делается в абстрактном классе, до всего остального компилятор додумается сам.</p>
<p>Например, так:</p>
<div id="EZOAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="KEYWORD">public</span> <span class="KEYWORD">class</span> Animal
{
  <span class="KEYWORD">public</span> <span class="KEYWORD">int</span> Id { <span class="KEYWORD">get</span>; <span class="KEYWORD">set</span>; }
  <span class="KEYWORD">public</span> <span class="KEYWORD">string</span> Name { <span class="KEYWORD">get</span>; <span class="KEYWORD">set</span>; }
  <span class="KEYWORD">public</span> <span class="KEYWORD">bool</span> CanFly { <span class="KEYWORD">get</span>; <span class="KEYWORD">set</span>; }
}</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Снаружи, для всех метаданных, это выглядит как обычное свойство, изнутри класса обращаться к нему тоже надо как к свойству. В общем, скомпилируется это дело в обычное свойство, в виде обертки над некоей приватной переменной. Естественно, как только мы захотим добавить какую-нибудь логику, тело свойства придется реализовать.</p>
<p>Если же мы хотим, чтобы свойство было доступно извне только для чтения, то синтаксис будет следующим:</p>
<div id="E3PAC">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre>  <span class="KEYWORD">public</span> <span class="KEYWORD">int</span> Id { <span class="KEYWORD">get</span>; <span class="ACCENT">private set;</span> }</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Совсем отказаться от объявления сеттера нельзя, так как свойство нельзя будет проинициализировать.</p>
<h3>Частичные методы (Partial Methods)<a name="ELAAE"></a></h3>
<p>В C# 2.0 появились частичные классы (partial class), которые сильно помогают при кодогенерации для отделения сгенерированного кода от рукописного (по сути, это реализация паттерна Generation Gap, встроенная в язык). Благодаря этому серьезно облегчилась работа с визуальными дизайнерами.</p>
<p>В LINQ2SQL или LNQ2Entity кодогенерация будет использоваться довольно активно. По этой причине решили не останавливаться на достигнутом, и в C# 3.0 введут частичные методы (partial methods).</p>
<p>По сути своей, частичные методы объявляются как обычные приватные методы с ключевым словом partial в начале и с пустым телом. Само тело метода может быть реализовано где угодно, но в том же классе. Если тело метода реализовано, то все вызовы компилятор переправит на него, если же реализации не будет, то компилятор просто выкинет вызов этого метода.</p>
<p>Пара важных нюансов:</p>
<ul style="list-style-type:square;list-style-image:none;list-style-position:outside;">
<li>Объявление частичного метода обязательно должно быть приватным.</li>
<li>Типом возвращаемого значения должен быть void.</li>
</ul>
<table class="note" border="0" width="98%">
<tbody>
<tr>
<td><strong>ПРИМЕЧАНИЕ</strong><br />
В принципе, частичные методы можно воспринимать как облегченную версию событий (event). Если есть обработчик (реализация частичного метода), вызов события обрабатывается, если же реализации нет – при вызове ничего не происходит.</td>
</tr>
</tbody>
</table>
<p>Для чего такая штука может пригодиться?</p>
<p>В первую очередь, как уже было сказано, для кодогенерации. Преимущества такого способа перед обычными событиями состоят в том, что события вынуждены выполнять множество проверок во время выполнения, а здесь даже пустого вызова не будет, от него избавится компилятор. Таким образом, эта конструкция очень выгодна в сценариях, критичных к производительности, например, в том же LINQ 2 SQL.</p>
<p>С помощью частичных методов довольно удобно обрабатывать различные ситуации с константами компиляции, например, реализовать тело логгера только в секции #if DEBUG … и спокойно использовать его, где надо. В Release версии все вызовы логгера будут автоматически удалены. Пустячок, а приятно. <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>Синтаксис<a name="EHBAE"></a></h3>
<p>Приятным бонусом является новый синтаксис инициализации объектов и массивов. Если тип оборудован рядом публичных свойств, то теперь нет необходимости сначала создавать экземпляр объекта, а затем по отдельности инициализировать необходимые свойства или же описывать специальные конструкторы, в задачу которых входит исключительно инициализация свойств из значений параметров. Теперь все стало гораздо проще – начальные значения можно указать сразу при создании объекта, все остальное возьмет на себя компилятор. Например, создание экземпляра класса, описывающего какого-нибудь зверька, может выглядеть примерно так:</p>
<div id="EMBAE">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="KEYWORD">new</span> Animal{ Id = 1, Name = <span class="STRING">"Eagle"</span>, CanFly = <span class="KEYWORD">true }</span></pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>а массива таких зверьков – так:</p>
<div id="EXBAE">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="KEYWORD">var</span> animals = <span class="KEYWORD">new</span> Animal[]
{
<span class="KEYWORD">  new</span> Animal{ Id = 1, Name = <span class="STRING">"Eagle"</span>,    CanFly = <span class="KEYWORD">true  </span>},
  <span class="KEYWORD">new</span> Animal{ Id = 2, Name = <span class="STRING">"Cat"</span>,      CanFly = <span class="KEYWORD">false </span>},
  <span class="KEYWORD">new</span> Animal{ Id = 3, Name = <span class="STRING">"Hedgehog"</span>, CanFly = <span class="KEYWORD">true  </span>}
};</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Ну и наконец, самая верхушка айсберга. Сейчас у нас готова практически вся механика для работы с запросами, осталось ее красиво обернуть. В качестве обертки выступает синтаксис запросов, очень похожий на SQL. Скажем, имея вышеприведенный набор зверьков, вывести тех из них, которые умеют летать, и отсортировать их по убыванию идентификаторов можно так:</p>
<div id="ESCAE">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="KEYWORD">var</span> q2 = <span class="KEYWORD">from</span> a <span class="KEYWORD">in</span> animals
  <span class="KEYWORD">where</span> a.CanFly
  <span class="KEYWORD">orderby</span> a.Id <span class="KEYWORD">descending</span>
  <span class="KEYWORD">select</span> <span class="KEYWORD">new</span> { a.Id, a.Name };</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>Понятно, что вся эта красивость превращается в уже пройденное нами:</p>
<div id="EHDAE">
<table class="code" border="0" width="98%">
<tbody>
<tr>
<td>
<pre><span class="KEYWORD">var</span> q = animals
  .Where(a =&gt; a.CanFly)
  .Select(a =&gt; <span class="KEYWORD">new</span> { a.Id, a.Name })
  .OrderByDescending(a =&gt; a.Id);</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>но первый вариант несколько приятнее&#8230; <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Таким образом, собственно от LINQ-а в язык будет встроен лишь этот неприхотливый синтаксис, а вся остальная функциональность, на которой построен LINQ, ценна и сама по себе.</p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/gltrainee.wordpress.com/41/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/gltrainee.wordpress.com/41/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/gltrainee.wordpress.com/41/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/gltrainee.wordpress.com/41/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/gltrainee.wordpress.com/41/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/gltrainee.wordpress.com/41/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/gltrainee.wordpress.com/41/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/gltrainee.wordpress.com/41/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/gltrainee.wordpress.com/41/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/gltrainee.wordpress.com/41/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/gltrainee.wordpress.com/41/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/gltrainee.wordpress.com/41/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gltrainee.wordpress.com&blog=3911599&post=41&subd=gltrainee&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://gltrainee.wordpress.com/2008/06/26/%d0%bd%d0%be%d0%b2%d1%8b%d0%b5-%d0%b2%d0%be%d0%b7%d0%bc%d0%be%d0%b6%d0%bd%d0%be%d1%81%d1%82%d0%b8-c-30/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e52f9678ec4a38aa487f3a4f64db85e9?s=96&#38;d=monsterid" medium="image">
			<media:title type="html">whitenie</media:title>
		</media:content>
	</item>
		<item>
		<title>Windows Workflow Foundation (Intro &#8211; lesson 1)</title>
		<link>http://gltrainee.wordpress.com/2008/06/26/%d0%b2%d0%b2%d1%83%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b2-windows-workflow-foundation/</link>
		<comments>http://gltrainee.wordpress.com/2008/06/26/%d0%b2%d0%b2%d1%83%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b2-windows-workflow-foundation/#comments</comments>
		<pubDate>Thu, 26 Jun 2008 17:25:03 +0000</pubDate>
		<dc:creator>whitenie</dc:creator>
				<category><![CDATA[WF]]></category>

		<guid isPermaLink="false">http://gltrainee.wordpress.com/?p=36</guid>
		<description><![CDATA[Как разработчиков наша задача состоит в том чтобы решать рельные бизнесс-задачи, но независимо от сложности задачи, даже комплексности, мы решаем их единообразно – большая зазача разбивается на более простые, те в свою очередь на еще более простые и т.д. &#8230; Врезультате мы получаем множество задач, но множество простых задач, которые гораздо легче осмыслить, выполнить и [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gltrainee.wordpress.com&blog=3911599&post=36&subd=gltrainee&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p class="MsoBodyText" style="text-align:justify;text-indent:35.3pt;"><a name="q-s6"></a><span>Как разработчиков наша задача состоит в том чтобы решать рельные бизнесс-задачи, но независимо от сложности задачи, даже комплексности, мы решаем их единообразно – большая зазача разбивается на более простые, те в свою очередь на еще более простые и т.д. &#8230; Врезультате мы получаем множество задач, но множество простых задач, которые гораздо легче осмыслить, выполнить и протестировать.</span><span id="more-36"></span></p>
<p class="MsoBodyText" style="text-align:justify;text-indent:35.3pt;"><a name="q-s60"></a><a name="q-s61"></a><span> </span></p>
<p class="MsoBodyText" style="text-align:justify;text-indent:35.3pt;"><a name="q-s62"></a><span>В традиционной на данный момент модели программирования мы реализуем решение задачи жестко зашивая его в програмный код. Наш код определяет «что делать» вместе с тем «как это делать» (осуществлять контроль над тем что делать). Мы также жестко кодируем правила поведения кода базирующиеся на значениях какихто параметров, срабатывания событий и текущего состояния приложения.</span></p>
<p class="MsoBodyText" style="text-align:justify;text-indent:35.3pt;"><a name="q-s63"></a><a name="q-s64"></a><span> </span></p>
<p class="MsoBodyText" style="text-align:justify;text-indent:35.3pt;"><a name="q-s65"></a><span>Workflow это просто упорядоченные серии шагов которые достигают некоторой предопределенной цели согласно некому набору правил &#8230; </span></p>
<p class="MsoBodyText" style="text-align:justify;text-indent:35.3pt;"><a name="q-s66"></a><a name="q-s67"></a><span> </span></p>
<p class="MsoBodyText" style="text-align:justify;text-indent:35.3pt;"><a name="q-s68"></a><span>Windows Workflow Foundation это платформа созданная компанией Microsoft для управления бизнесс-процессами – т.е. потоками работ. Фактически это же мы делаем ежедневно руками. Мы так же разбиваем задачи на более простые и решаем их по отлельности. В виде Workflow Foundation компания Microsoft предоставила програмную модель для автоматизации и декларизации этого непосильного ручного труда<a name="q-s69"></a><a name="q-s610"></a> </span><span style="font-family:Wingdings;"><span>J</span></span></p>
<p class="MsoBodyText" style="text-align:justify;text-indent:35.3pt;"><span> </span></p>
<p class="MsoBodyText" style="text-align:justify;text-indent:35.3pt;"><a name="q-s611"></a><span>WF предоставляет объектную модель и средства разработки приложений основанных на принципах рабочих потоков и может использоваться в самом широком спектре сценариев — от взаимодействия с пользователем до управления распределенными бизнес-процессами &#8230; </span></p>
<p class="MsoBodyText" style="text-align:justify;"><a name="q-s612"></a><a name="q-s613"></a><span> </span></p>
<p class="MsoBodyText" style="text-align:justify;"><a name="q-s614"></a><a name="q-s615"></a><span style="color:black;">Если посмотреть на данную схему<a name="q-s616"></a><a name="q-s617"></a><a name="q-s618"></a></span></p>
<p class="MsoBodyText" style="text-align:justify;"><a href="http://gltrainee.files.wordpress.com/2008/06/untitled.gif"><img class="alignnone size-medium wp-image-37" src="http://gltrainee.files.wordpress.com/2008/06/untitled.gif?w=300&#038;h=201" alt="" width="300" height="201" /></a></p>
<p class="MsoBodyText" style="text-align:center;" align="center"><span style="color:blue;"><!--[if gte vml 1]&gt;                     &lt;![endif]--><!--[if !vml]--><!--[endif]--></span></p>
<p class="MsoBodyText" style="text-align:justify;"><a name="q-s620"></a><a name="q-s621"></a><a name="q-s622"></a><a name="q-s623"></a><span style="color:black;">можно увидеть, что </span><span>Workflow <span style="color:black;">не является приложением которое мы можем взять и запустить, жизнью и деятельностью </span>Workflow <span style="color:black;">управляет </span></span><a name="q-s624"></a><span style="color:black;">Workflow</span><span style="color:black;"> </span><a name="q-s625"></a><span style="color:black;">Runtime</span><span style="color:black;"> который умеет запускать, останавливать </span><span>Workflow <span style="color:black;">а также сообщать о событиях происходящих внутри </span>Workflow.</span></p>
<p class="MsoBodyText" style="text-align:justify;"><span style="color:black;">Для того чтобы воркфлоу всетаки заставить выполняться необходимо еще одно приложение которое служило бы ему хостом и через </span><a name="q-s626"></a><span style="color:black;">Workflow</span><span style="color:black;"> </span><a name="q-s627"></a><span style="color:black;">Runtime</span><span style="color:black;"> управляло бы безопасностью жизнедеятельности </span><span>Workflow<span style="color:black;">. </span></span><a name="q-s628"></a><span style="color:black;">Workflow</span><span style="color:black;"> </span><a name="q-s629"></a><span style="color:black;">Runtime</span><span style="color:black;"> отвечает за хранение состояния, загрузку и активацию </span><a name="q-s630"></a><span style="color:black;">Workflow</span><span style="color:black;">. В роли хост прилоежения могут служить все существующие на сегодня виды приложений.</span><a name="q-s631"></a><span> </span></p>
<p class="MsoBodyText" style="text-align:justify;"><a name="q-s633"></a><a name="q-s634"></a><span style="color:black;">Другими словами, </span><a name="q-s635"></a><span style="color:black;">Workflow</span><span style="color:black;"> </span><span style="color:black;">– это набор действий координирующих работу программы.</span></p>
<p class="MsoBodyText" style="text-align:justify;">
<p class="MsoBodyText" style="text-align:justify;"><span>Примеры действий:</span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:-14.15pt;"><a name="q-s639"></a><a name="q-s640"></a><a name="q-s641"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><span>направить работу руководителю</span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:-14.15pt;"><a name="q-s642"></a><a name="q-s643"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span> ·<span> </span></span></span><!--[endif]--><span>переделать</span></p>
<p class="MsoBodyText" style="text-align:justify;"><span> </span></p>
<p class="MsoBodyText" style="text-align:justify;"><a name="q-s644"></a><a name="q-s645"></a><a name="q-s646"></a><span style="color:black;">Workflow</span><span style="color:black;"> представляется в виде процесса:</span></p>
<p class="MsoBodyText" style="text-align:justify;"><a name="q-s647"></a><a name="q-s648"></a><span> </span></p>
<p class="MsoBodyText" style="text-align:justify;"><a name="q-s649"></a><span>- как блоксхема (sequential workflow):</span><a href="http://gltrainee.files.wordpress.com/2008/06/untitled1.gif"><img class="aligncenter size-medium wp-image-38" src="http://gltrainee.files.wordpress.com/2008/06/untitled1.gif?w=172&#038;h=159" alt="" width="172" height="159" /></a></p>
<p class="MsoBodyText" align="center"><a name="q-s654"></a><span style="color:blue;"><!--[if gte vml 1]&gt;   &lt;![endif]--><!--[if !vml]--><!--[endif]--></span><a name="q-s655"></a><a name="q-s656"></a><a name="q-s657"></a><a name="q-s658"></a></p>
<p class="MsoBodyText" style="text-align:justify;"><a name="q-s660"></a><span lang="EN-US"> </span></p>
<p class="MsoBodyText" style="text-align:justify;"><a name="q-s661"></a><span>- как диаграмма состояний (state machine workflow (конечный автомат)):</span></p>
<p class="MsoBodyText" style="text-align:justify;"><a name="q-s662"></a><a name="q-s663"></a></p>
<p style="text-align:center;"><img class="size-medium wp-image-39 aligncenter" src="http://gltrainee.files.wordpress.com/2008/06/untitled235.gif?w=179&#038;h=142" alt="" width="179" height="142" /></p>
<p class="MsoBodyText" style="text-align:justify;"><span> </span></p>
<p class="MsoBodyText" style="text-align:center;" align="center"><a name="q-s664"></a><a name="q-s665"></a><a name="q-s666"></a><span style="color:blue;"><!--[if gte vml 1]&gt;   &lt;![endif]--><!--[if !vml]--><!--[endif]--></span><a name="q-s667"></a></p>
<p class="MsoBodyText" style="text-align:justify;"><span> </span></p>
<p class="MsoBodyText" style="text-align:justify;text-indent:21.2pt;"><a name="q-s670"></a><a href="http://gltrainee.files.wordpress.com/2008/06/untitled235.gif"></a><span>Рассмотрим виды workflow более подробно:</span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:-14.15pt;"><a name="q-s671"></a><a name="q-s672"></a><a name="q-s673"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><span>Sequential Workflow (последовательній работопоток) имееет последователььную структуру которая и определяет его порядок исполнения «Шаг1-&gt;Шаг2-&gt;Шаг3». Такие сценарии имеют четко определенные начало и конец, но тем не менее не лишены и гибкости полнейшего зацикливания.</span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:-14.15pt;"><a name="q-s674"></a><a name="q-s675"></a><a name="q-s676"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><span style="color:black;">State Machine Workflow (конечный астомат операций) имеет вид графа с иногда болтающимися вершинами, последовательностью выполнения управляют внешние события, вследствие чего система переходит из одного состояния в другое.</span></p>
<p class="MsoBodyText" style="text-align:justify;"><a name="q-s677"></a><span>&#8230; выполнение и тех и других воркфлоу может регламентироваться небором правил «правило1 – шаг1, правило 2 – шаг2»</span></p>
<p class="MsoBodyText" style="text-align:justify;"><a name="q-s678"></a><a name="q-s679"></a><span> </span></p>
<p class="MsoBodyText" style="text-align:justify;"><a name="q-s680"></a><span>Зачем же это все нужно ? &#8230; <a name="q-s681"></a><span style="color:black;">Workflow даёт нам ускорение в разработке в нескольно раз !</span></span></p>
<p class="MsoBodyText" style="text-align:justify;"><span style="color:black;"> </span></p>
<p class="MsoBodyText" style="text-align:justify;"><a name="q-s682"></a><span>Workflow также имеет ряд дополнительной функциональности: </span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:-14.15pt;"><a name="q-s683"></a><a name="q-s684"></a><a name="q-s685"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><em><span style="text-decoration:underline;"><span>Поддержка длительных процессов с сохранением состояния</span></span></em><span style="text-decoration:underline;"><span>.</span></span><span> Т.е. если, к примеру, работа <a name="q-s686"></a><span style="color:black;">Workflow в определенный момент требует какого нить внешнего событися – то на время ожидания состояние Workflow может быть сохранено в базу данных а затем по наступлению этого желаемого события быть реактивировано для дальнейшего выполнения с восстановлением предъидущего состояния</span>.</span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:-14.15pt;"><a name="q-s687"></a><a name="q-s688"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><em><span style="text-decoration:underline;"><span>Гибкая и легко изменяемая последовательность шагов</span></span></em><em><span>.</span></em><span> Т.е. в <a name="q-s689"></a><span style="color:black;">Workflow состояшего из набора шагов эти шаги можно переставлять не меняя ни строчки кода</span>.</span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:-14.15pt;"><a name="q-s690"></a><a name="q-s691"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><em><span style="text-decoration:underline;"><span>Прозрачность исполнения</span></span></em><span>. – т.е. Workflow можно дебажить прямо в дизайнере, так же каждый шаг в Workflow может оповещать о ходе своего выполнения.</span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:-14.15pt;"><a name="q-s692"></a><a name="q-s693"></a><a name="q-s694"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><em><span style="text-decoration:underline;"><span style="color:black;">Инфраструктура для логов и трассировки</span></span></em><span style="color:black;">. Т.е. каждое действие в Workflow может быть залогировано и отслежено его выполнение в удобной для разработчика форме</span><span>.</span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:-14.15pt;"><a name="q-s695"></a><a name="q-s696"></a><a name="q-s697"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><em><span style="text-decoration:underline;"><span style="color:black;">Персистентность</span></span></em><span style="color:black;"> имеет родственность с пунктом первым, состоит в автоматическом сбрасывании состояния в базу данных и затем восстановления из нее когда нужно</span><span>.</span></p>
<p class="MsoBodyText" style="text-align:justify;"><a name="q-s698"></a><a name="q-s699"></a><span> </span></p>
<p class="MsoBodyText" style="text-align:justify;text-indent:21.2pt;"><span>В результате можем сделать вывод о ключевых концепциях и составных частях </span><span lang="EN-US">Windows</span><span lang="EN-US"> </span><span lang="EN-US">Workflow</span><span lang="EN-US"> </span><span lang="EN-US">Foundation</span><span>.</span></p>
<p class="MsoBodyText" style="text-align:justify;text-indent:21.2pt;"><span>К основным концепциям относится то что </span><span lang="EN-US">Workflow</span><span> это набор действый, что </span><span lang="EN-US">Workflow</span><span>ы могут исполняться только в хост-процессе (любом приложении), а также то что разработчики, т.е. мы, можем создавать свои собственные библиотеки действий (</span><span lang="EN-US">custom</span><span lang="EN-US"> </span><span lang="EN-US">activities</span><span>).</span></p>
<p class="MsoBodyText" style="text-align:justify;text-indent:21.2pt;"><span>К основным компонентам </span><span lang="EN-US">Workflow</span><span> относятся: базовая библиотека действий, среда исполнения , сервисы (как стандартные так и кастом) &#8230; а также визуальный дизайнер являющийся одной из основных фиче </span><span lang="EN-US">Workflow</span><a name="ue-3"></a><a name="pl2j"></a><span>.</span></p>
<p class="MsoBodyText" style="text-align:justify;text-indent:21.2pt;"><span> </span></p>
<p class="MsoBodyText" style="text-align:justify;text-indent:21.2pt;"><span>Обработчики выполнения вызываемые планировциком &#8230; это просто методы операций &#8230; поэтому любой из них может возбудить исключение и если оно не обрабатывается то </span><span lang="EN-US">Workflow</span><span> просто заканчивает своё выполнение. Необработанное исключение не всплывает в хост приложение, однако вытащить его там всетаки можно через свойство </span><span lang="EN-US">Exception</span><span> аргументов события </span><span lang="EN-US">Terminated</span><span>. Исключение не всплывет в хост-приложение т.к. в </span><span lang="EN-US">Windows</span><span lang="EN-US"> </span><span lang="EN-US">Workflow</span><span> исключения распространяются асинхронно, соответственно и обрабатываться должны тоже асинхронно – для этого всего компания Microsoft придумала такое состояние активити как </span><span lang="EN-US">Faulting</span><span> – когда работа (операция) валится (в ней возникает исключение) то она переходит в состояние </span><span lang="EN-US">Faulting</span><span>, другие операции выполняющиеся в этом </span><span lang="EN-US">Workflow</span><span> в этот же момент отменяются переходя срочно в состояние </span><span lang="EN-US">Canceling</span><span>, для поимки исключение в композитных работах (операциях могущих иметь подопереции) предусмотрен режим </span><span lang="EN-US">Fault</span><span lang="EN-US"> </span><span lang="EN-US">Handler</span><span> в который мы можем добавлять хендлеры (это такие стандартные активити для поимки исключений) которые будут ловить конкретные виды иссключений &#8230; далее можно выполнить какието восстановительные работы и/или транслировать иссключение в хост-приложение<a name="pl2j0"></a>.<a name="ue-30"></a></span></p>
<p class="MsoBodyText" style="text-align:justify;text-indent:21.2pt;"><span> </span></p>
<p class="MsoBodyText" style="text-align:justify;"><span>Подберемся ближе к непосредственной разработке в терминах </span><span lang="EN-US">Workflow</span><span> &#8230;<a name="s2lf"></a><br />
<span> </span></span><span lang="EN-US">Workflow</span><span> могут быть созданы в трех ипостасях:</span></p>
<p class="MsoBodyText" style="margin-left:0.5in;text-align:justify;text-indent:-0.25in;"><!--[if !supportLists]--><span style="font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><span>только разметка (</span><span lang="EN-US">XAML</span><span>)</span></p>
<p class="MsoBodyText" style="margin-left:0.5in;text-align:justify;text-indent:-0.25in;"><!--[if !supportLists]--><span style="font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><span>разметка + код</span></p>
<p class="MsoBodyText" style="margin-left:0.5in;text-align:justify;text-indent:-0.25in;"><!--[if !supportLists]--><span style="font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><span>только код</span></p>
<p class="MsoBodyText" style="text-align:justify;"><a name="fxab"></a><span><span> </span><span> </span>Разметка в </span><span lang="EN-US">Workflow</span><span> определяет структуру </span><span lang="EN-US">Workflow</span><span>, а соответственно определяться должна структурой бизнес-логики, когда же разметка объеденяется с кодом то разметка </span><span lang="EN-US">XAML</span><span> определяет структуру </span><span lang="EN-US">Workflow</span><span>, а код логику, если же </span><span lang="EN-US">Workflow</span><span> представлен в виде только кода тогда </span><span lang="EN-US">Workflow</span><span> создается в конструкторе основного класса, но концептуально это никакого отличия не вносит. Обычно компилятор генерирует </span><span lang="EN-US">Workflow</span><span> как код + разметка &#8230;<a name="i8z2"></a></span></p>
<p class="MsoBodyText" style="text-align:justify;"><span><span> </span>Когда </span><span lang="EN-US">Workflow</span><span> готов к работе то при запуске компилятором </span><span lang="EN-US">Workflow</span><span lang="EN-US"> </span><span lang="EN-US">wcf</span><span>.</span><span lang="EN-US">exe</span><span> он переводится в обычный </span><span lang="EN-US">C</span><span># код (третий вариант создания) а затем джаст ин таймом в </span><span lang="EN-US">CIL</span><span> &#8230;<a name="m8h5"></a><a name="m8h50"></a></span></p>
<p class="MsoBodyText" style="text-align:justify;"><span> </span></p>
<p class="MsoBodyText" style="text-align:justify;"><span> </span></p>
<p class="MsoBodyText" style="text-align:justify;"><span><span> </span>Как итог обзора хотелось бы дать небольшую сравнительную характеристику подхода к разработке бизнесс-логики с </span><span lang="EN-US">Workflow</span><span> и без него<a name="vapz"></a>.</span></p>
<p class="MsoBodyText" style="text-align:justify;"><span> </span></p>
<p class="MsoBodyText" style="text-align:justify;"><span lang="EN-US">Workflow</span><span>:<a name="tgzk"></a></span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:0;"><a name="tgzk0"></a><a name="tgzk1"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><span lang="EN-US">Наглядность </span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:0;"><a name="tgzk11"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><span lang="EN-US">Расширяемость </span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:0;"><a name="tgzk12"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><span lang="EN-US">Обработка ошибок </span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:0;"><a name="tgzk13"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><span lang="EN-US">Трекинг </span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:0;"><a name="tgzk14"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><span lang="EN-US">Персистентность </span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:0;"><a name="tgzk15"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><span lang="EN-US">Unit-тесты </span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:0;"><a name="tgzk16"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><span lang="EN-US">Ускорение разработки </span></p>
<p class="MsoBodyText" style="text-align:justify;"><a name="rgac"></a><span> </span></p>
<p class="MsoBodyText" style="text-align:justify;"><span lang="EN-US">Клас</span><span>с</span><span lang="EN-US">ический подход:<a name="rm_o"></a></span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:0;"><a name="rm_o0"></a><a name="rm_o1"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><span lang="EN-US">Привычность </span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:0;"><a name="rm_o2"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><span lang="EN-US">Жестко зашитая логика </span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:0;"><a name="rm_o21"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><span lang="EN-US">Ручной трекинг </span></p>
<p class="MsoBodyText" style="margin-left:0;text-align:justify;text-indent:0;"><a name="rm_o22"></a><!--[if !supportLists]--><span style="font-size:9pt;font-family:Symbol;"><span>·<span> </span></span></span><!--[endif]--><span lang="EN-US">Ручная обработка ошибок </span></p>
<p class="MsoBodyText" style="text-align:justify;"><span lang="EN-US"> </span></p>
<p class="MsoBodyText" style="text-align:justify;text-indent:35.45pt;"><a name="fe4v"></a><span>Надеюсь данная вольно написанная статья помогла вам получить хоть частичную иллюзию понимания </span><span lang="EN-US">Windows</span><span lang="EN-US"> </span><span lang="EN-US">Workflow</span><span lang="EN-US"> </span><span lang="EN-US">Foundation</span><span lang="EN-US"> </span><span style="font-family:Wingdings;"><span>J</span></span><span>.</span></p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/gltrainee.wordpress.com/36/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/gltrainee.wordpress.com/36/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/gltrainee.wordpress.com/36/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/gltrainee.wordpress.com/36/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/gltrainee.wordpress.com/36/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/gltrainee.wordpress.com/36/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/gltrainee.wordpress.com/36/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/gltrainee.wordpress.com/36/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/gltrainee.wordpress.com/36/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/gltrainee.wordpress.com/36/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/gltrainee.wordpress.com/36/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/gltrainee.wordpress.com/36/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gltrainee.wordpress.com&blog=3911599&post=36&subd=gltrainee&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://gltrainee.wordpress.com/2008/06/26/%d0%b2%d0%b2%d1%83%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b2-windows-workflow-foundation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e52f9678ec4a38aa487f3a4f64db85e9?s=96&#38;d=monsterid" medium="image">
			<media:title type="html">whitenie</media:title>
		</media:content>

		<media:content url="http://gltrainee.files.wordpress.com/2008/06/untitled.gif?w=300" medium="image" />

		<media:content url="http://gltrainee.files.wordpress.com/2008/06/untitled1.gif?w=172" medium="image" />

		<media:content url="http://gltrainee.files.wordpress.com/2008/06/untitled235.gif?w=179" medium="image" />
	</item>
		<item>
		<title>Windows Workflow Foundation (Введение)</title>
		<link>http://gltrainee.wordpress.com/2008/06/07/windows-workflow-foundation-%d0%b2%d0%b2%d0%b5%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5/</link>
		<comments>http://gltrainee.wordpress.com/2008/06/07/windows-workflow-foundation-%d0%b2%d0%b2%d0%b5%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5/#comments</comments>
		<pubDate>Sat, 07 Jun 2008 12:41:45 +0000</pubDate>
		<dc:creator>masalov</dc:creator>
				<category><![CDATA[WF]]></category>
		<category><![CDATA[Activity]]></category>
		<category><![CDATA[Local services]]></category>
		<category><![CDATA[Workflow]]></category>

		<guid isPermaLink="false">http://gltrainee.wordpress.com/?p=15</guid>
		<description><![CDATA[Windows Workflow Foundation (WWF) представляет собой технологию Microsoft для определения, выполнения и управления рабочими потоками (workflows). Windows Workflow Foundation является подсистемой .NET Framework 3.0, входящей в состав операционной системы Windows Vista. WWF ориентирована на визуальное программирование, используя при этом декларативную модель программирования.

Базовые понятия
Как известно, логику работы программной системы можно представить в виде схемы. Обычно схемы [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gltrainee.wordpress.com&blog=3911599&post=15&subd=gltrainee&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Windows Workflow Foundation (WWF) представляет собой технологию Microsoft для определения, выполнения и управления рабочими потоками (workflows). Windows Workflow Foundation является подсистемой .NET Framework 3.0, входящей в состав операционной системы Windows Vista. WWF ориентирована на визуальное программирование, используя при этом декларативную модель программирования.</p>
<p><span id="more-15"></span><br />
<strong>Базовые понятия</strong></p>
<p>Как известно, логику работы программной системы можно представить в виде схемы. Обычно схемы используют на этапе проектирования, но во время разработки про них забывают, так как существующие инструменты синхронизации схем и кода не вполне эффективны. Так было до появления WF. Теперь у разработчиков есть возможность создавать в Visual Studio схемы, синхронизированные с кодом.</p>
<p>Для описания логики работы программ (алгоритмов) в WF используются два основных понятия – <strong>activity </strong>и <strong>workflow</strong>.</p>
<p><strong>Activity </strong>– это любое действие, которое логически считается элементарным (неделимым) или, другими словами, activity – это шаг алгоритма. С английского activity переводится как 1) «деятельность» 2) «активность». В разных статьях используются следующие синонимы: задание, задача, функция, операция, шаг процесса, элемент работы.</p>
<p>Активность реализована в классе System.Workflow.ComponentModel.Activity (находится в сборке System.Workflow.Activities.dll).</p>
<p>У класса Activity есть множество наследников, часть из которых служит для организации иерархий активностей. К таким классам относятся CompositeActivity и все его наследники, например, IfElseActivity, WhileActivity и т.д. Другая часть классов реализует активности, типичные для многих проектов – это, например, InvokeWebServiceActivity, InvokeWorkflowActivity и т.д. Типичные активности отображаются в Visual Studio в окне Toolbox (Ctrl+Alt+X).</p>
<p><strong>Workflow </strong>– это последовательность или иерархия активностей (activity). Переводится как «последовательность выполняемых действий». Синонимы: поток работ, работопоток, рабочий процесс, ход работ, бизнес-процесс, схема процесса, сценарий, модель процесса, модель бизнес-процесса, последовательность операций.</p>
<p>Если activity можно рассматривать как команду, специфичную для предметной области, то workflow – это дерево команд.</p>
<p>Существуют два класса (находятся в сборке System.Workflow.Activities.dll) с реализацией workflow:</p>
<p>*<strong> System.Workflow.Activities.SequentialWorkflowActivity</strong><br />
Поток, в котором все активности выполняются последовательно.</p>
<p>* <strong>System.Workflow.Activities.StateMachineWorkflowActivity</strong><br />
Событийно-управляемый поток, в котором активности вызываются непоследовательно в ответ на внешние события. Этот тип workflow подходит для создания различных мастеров (wizard).</p>
<p>Надо заметить, что среди предков у обоих классов есть класс CompositeActivity. Т.е. любой workflow является контейнером для других activity.</p>
<p><img src="/DOCUME~1/masalov/LOCALS~1/Temp/moz-screenshot.jpg" alt="" /><a href="http://gltrainee.files.wordpress.com/2008/06/5.jpg"><img class="aligncenter size-full wp-image-27" src="http://gltrainee.files.wordpress.com/2008/06/5.jpg" alt="" /></a></p>
<p>Примечание: наиболее часто повторяющиеся структуры, т.е. характерные последовательности активностей в workflow называют workflow-паттернами (workflow patterns или wf-patterns).</p>
<p><strong>Workflow runtime </strong>– исполняющая среда; служит для выполнения workflow, т.е. исполняющая среда «обходит» дерево workflow и «оживляет» activity. Синонимы: workflow engine, движок, механизм исполнения.</p>
<p>Исполняющая среда представлена в классе System.Workflow.Runtime.WorkflowRuntime, а также в ряде наследников класса System.Workflow.Runtime.Hosting.WorkflowRuntimeService (находятся в сборке System.Workflow.Runtime.dll).</p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/gltrainee.wordpress.com/15/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/gltrainee.wordpress.com/15/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/gltrainee.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/gltrainee.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/gltrainee.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/gltrainee.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/gltrainee.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/gltrainee.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/gltrainee.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/gltrainee.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/gltrainee.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/gltrainee.wordpress.com/15/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gltrainee.wordpress.com&blog=3911599&post=15&subd=gltrainee&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://gltrainee.wordpress.com/2008/06/07/windows-workflow-foundation-%d0%b2%d0%b2%d0%b5%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/68d963ae477c9c1d15463d3a10c23b56?s=96&#38;d=monsterid" medium="image">
			<media:title type="html">masalov</media:title>
		</media:content>

		<media:content url="/DOCUME~1/masalov/LOCALS~1/Temp/moz-screenshot.jpg" medium="image" />

		<media:content url="http://gltrainee.files.wordpress.com/2008/06/5.jpg" medium="image" />
	</item>
	</channel>
</rss>