<?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:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Trainee's Weblog &#187; .NET</title>
	<atom:link href="http://gltrainee.wordpress.com/category/net/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 &#187; .NET</title>
		<link>http://gltrainee.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://gltrainee.wordpress.com/osd.xml" title="Trainee&#8217;s Weblog" />
		<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>
	</channel>
</rss>