Зачастую бывает нужно инициализировать тип с некоторыми заранее заданными значениями свойств, отличными от значений по умолчанию. Допустим, у нас есть класс Forum:
Код C# 3.0
public class Forum {
string _name;
string _admin;
string _url;
int _membersCount;
public string Name {
get { return _name; } set { _name = value; }
}
public string Admin {
get { return _admin; } set { _admin = value; }
}
public string URL {
get { return _url; } set { _url = value; }
}
public int MembersCount {
get { return _membersCount; } set { _membersCount = value; }
}
}
Код VB.NET 9.0
Public Class Forum
Private _name As String
Private _admin As String
Private _url As String
Private _membersCount As Integer
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Public Property Admin() As String
Get
Return _admin
End Get
Set(ByVal value As String)
_admin = value
End Set
End Property
Public Property URL() As String
Get
Return _url
End Get
Set(ByVal value As String)
_url = value
End Set
End Property
Public Property MembersCount() As Integer
Get
Return _membersCount
End Get
Set(ByVal value As Integer)
_membersCount = value
End Set
End Property
End Class
Для того, чтобы объявить форум Vingrad, нам пришлось бы писать вот такое:
Код C# 3.0
Forum vingrad = new Forum();
vingrad.Admin = "WoWa";
vingrad.MembersCount = 17000;
vingrad.Name = "Vingrad";
vingrad.URL = " https://forum.vingrad.ru ";
Код VB.NET 9.0
Dim vingrad As New Forum
vingrad.Admin = "WoWa"
vingrad.MembersCount = 17000
vingrad.Name = "Vingrad"
vingrad.URL = " https://forum.vingrad.ru "
К счастью, в C# 3.0 появилась такая вот конструкция:
Код C# 3.0
Forum vingrad = new Forum(){Admin = "WoWa",
MembersCount = 17000,
Name = "Vingrad",
URL = " https://forum.vingrad.ru "};
Код VB.NET 9.0
Dim vingrad As New Forum {Admin:= "WoWa", _
MembersCount:= 17000, _
Name:= "Vingrad", _
URL:= " https://forum.vingrad.ru "}
Честно говоря, мне не очень понравился синтаксис VB.NET с:=, уж больно это напоминает Паскаль...:)
Эта конструкция существенно упрощает составление запросов. Скажем, мы можем написать
Код C# 3.0
IEnumerable<Forum> makeMeSuperAdmin = forums.Select(
forum => new Forum {
Admin = "Exception",
|
MembersCount = forum.MembersCount,
Name = forum.Name,
URL = forum.URL});
и даже
Код C# 3.0
string[] forumNames = {"Vingrad", "RSDN", "GotDotNet"};
IEnumerable<Forum> myOwnForums = forumNames.Select(
forumName => new Forum {
Admin = "Exception",
MembersCount = 1000000,
Name = forumName,
URL = "https://" + forumName + ".ru"});
Ну а если писать, используя стандартную запись для операторов запросов, выйдет вот что:
Код C# 3.0
string[] forumNames = { "Vingrad", "RSDN", "GotDotNet"};
IEnumerable<Forum> myOwnForums = from forumName in forumNames
select new Forum {
Admin = "Exception",
MembersCount = 1000000,
Name = forumName,
URL = "https://" + forumName + ".ru"};
Код VB.NET 9.0
Dim forumNames() As String = {"Vingrad", "RSDN", "GotDotNet"}
Dim myOwnForums As IEnumerable(Of Forum) = _
Select New Forum { _
Admin:= "Exception", _
MembersCount:= 1000000, _
Name:= forumName, _
URL:= "https://" + forumName + ".ru"} _
From forumName In forumNames
Таким образом, мы получаем из массива string перечисление IEnumerable<Forum>.
Анонимные типы
У Вас бывали ситуации, что нужно объявить класс только для одноразового использования? Нет? Значит, будут:) Допустим, перед нами стоит задача вывести на консоль только данные о названии и количестве участников форума. Представим, что Forum – довольно большой класс, и использование его при выводе на консоль всего нескольких свойств может понизить производительность из-за большого расхода памяти. Какие у нас есть выходы?
1) Без LINQ и анонимных типов
Рациональные методы отсутствуют (то есть без расхода памяти и с понятным кодом)
2) С LINQ, без анонимных типов
Создать структуру ForumStatistics со свойствами ForumName и MembersCount. Затем делать выборку вот таким запросом:
Код C# 3.0
IEnumerable<Forum> forums = //...
IEnumerable<ForumStatistics> forumStats = from forum in forums
select new ForumStatistics {
|
MembersCount = forum.MembersCount,
Name = forum.Name};
Код VB.NET 9.0
Dim forums As IEnumerable(Of Forum) = '...
Dim forumStats As IEnumerable(Of ForumStatistics) = _
Select New ForumStatistics { _
MembersCount:= forum.MembersCount, _
Name:= forum.Name} _
From forum In forums
3) C LINQ и анонимными типами
Здесь всё ещё проще. Нам даже не нужно создавать структуру ForumStatistics. Компилятор создаcт её автоматически, что сохранит нам время, а следовательно, деньги:)
Сейчас позволю себе небольшое лирическое отступление, т.к. не всё может быть понятно.
В C# 3.0 и VB.NET 9.0 можно писать код без объявления типов: компилятор сам поймёт, какой тип использовать. Например, код
Код C# 3.0
string s = "Bob";
int n = 32;
bool b = true;
Код VB.NET 9.0
Dim s As String = "Bob"
Dim n As Integer = 32
Dim b As Boolean = True
можно переписать, как
Код C# 3.0
var s = "Bob";
var n = 32;
var b = true;
Код VB.NET 9.0
Dim s = "Bob";
Dim n = 32
Dim b = True
, не теряя функциональности и производительности. С таким кодом даже работает IntelliSense! Правда, на такие объявления есть несколько ограничений:
i) Выражение всегда должно инициализироваться!
ii) Таким образом нельзя объявлять перечислимые типы
iii) Нельзя инициализировать выражение null’ем
Зачем же нужен этот «изврат», если можно так выразиться? Ответ прост: он позволяет не морочить себе голову при объявлении некоторых сложных типов и он также позволяет объявлять анонимные типы. Давайте рассмотрим наш пример. Код из пункта 2 можно переписать так:
Код C# 3.0
IEnumerable<Forum> forums = //...
var forumStats = from forum in forums
select new {
MembersCount = forum.MembersCount,
Name = forum.Name};
Код VB.NET 9.0
Dim forums As IEnumerable(Of Forum) = '...
Dim forumStats = _
Select New { _
MembersCount:= forum.MembersCount, _
Name:= forum.Name} _
From forum In forums
Самое приятное, что для анонимных типов по-прежнему доступен IntelliSense:
|
Впрочем, о поддержке IntelliSense, да и LINQ в VS 2005 мы поговорим позднее.
Если посмотреть Reflector’ом в сгенерированную сборку, видно, что компилятор сгенерировал анонимный тип _Anonymous_Main_7_1C. Кстати, использование анонимных типов имеет и обратную сторону: новички могут использовать их где попало, что, разумеется, затруднит чтение и понимание кода. Например, станет возможным творить вот такие «извраты»:
Код C# 3.0
var bob = new { Name = "Bob", Age = 51, CanCode = true };
var jane = new { Age = 29, FirstName = "Jane" };
var couple = new {
Husband = new { bob.Name, bob.Age },
Wife = new { Name = jane.FirstName, jane.Age }
};
int ha = couple.Husband.Age; // ha == 51
string wn = couple.Wife.Name; // wn == "Jane"
Код VB.NET 9.0
Dim bob = New {Name:= "Bob", Age:= 51, CanCode:= True}
Dim jane = New {Age:= 29, FirstName:= "Jane"}
Dim couple = New { _
Husband:= New {bob.Name, bob.Age}, _
Wife:= New {Name:= jane.FirstName, jane.Age} _
}
Dim ha As Integer = couple.Husband.Age ' ha = 51
Dim wn As String = couple.Wife.Name ' wn = "Jane"
Кстати, свойства Husband и Wife получают имена Name и Age от соответствующих свойств bob и jane, им переданных. Можно написать и более подробно:
Код C# 3.0
var couple = new {
Husband = new { Name = bob.Name, Age = bob.Age },
Wife = new { Name = jane.FirstName, Age = jane.Age }
};
Код VB.NET 9.0
Dim couple = New { _
Husband:= New { Name:= bob.Name, Age:= bob.Age }, _
Wife:= new { Name:= jane.FirstName, Age:= jane.Age } _
}