Трюки с анонимными типами в C#
автор evteev, Мар.09, 2013, рубрики C/C++/C#
Пусть читатели еще немного поломают ломают голову над задачками из предыдущего поста - свои ответы я опубликую еще через неделю. Хотя, должен отметить, читатели просто молодцы и отлично справляются с решением задачек. А я тем временем опубликую оставшуюся часть материала презентации на SECR.
Представим себе ситуацию, что в мы создали некоторый метод в котором хотели бы использовать список анонимных типов. Например, описываемых вот так:
var beatleJohn = new { FirstName = "John", LastName = "Lennon" };
При этом мы хотим сохранить строгую типизацию списка, поэтому логичным видится использование обобщенного класса List
. Однако, возникает вопрос, как нам чисто синтаксически создать обобщенный список не зная имени типа - фактически для нас анонимные типы, как и следует из названия, являются безымянными. Тут нужно вспомнить о технике создания обобщенной коллекции по экземпляру типа элемента коллекции.
�?спользование этого метода может выглядеть так:
var beatles = (new[] { beatleJohn }).ToList();
В результате мы получаем строго типизированный список, тип которого легко узнать воспользовавшись Console.WriteLine(beatles.GetType())
: выводит симпатичное имя System.Collections.Generic.List`1[<>f__AnonymousType0`2[System.String,System.String]]
, однако это знание нам просто для интереса и на практике никак не пригодится.
С полученным списком мы можем работать следующим образом:
beatles.Add(new { FirstName = "Paul", LastName = "McCartney" });
beatles.Add(new { FirstName = "George", LastName = "Harrison" });
beatles.Add(new { FirstName = "Ringo", LastName = "Starr" });
foreach (var beatle in beatles)
{
Console.WriteLine(beatle.FirstName + " " + beatle.LastName);
}
Хорошо, так мы можем создавать обобщенные коллекции анонимных типов, но что мешает воспользоваться этой техникой для...
Перед тем как читать дальше, я прошу слабонервных и легко восприимчивых к грязным трюкам закрыть глаза.
... для того, чтобы возвращать анонимные типы из методов.
Предположим, что у нас есть следующий метод:
static object GetBeatleName() { return new { First = "John", Last = "Lennon" }; }
Метод возвращает некий объект, что замечательно, однако чтобы этим объектом можно было удобно пользоваться, прибегнем к описанному выше методу и определим вспомогательный обобщенный метод для приведения типов:
static T CastType(object obj, T type) { return (T)obj; }
которым воспользуемся так:
var beatle = CastType(obj, new {First = "", Last = ""});
Как и в предыдущем примере мы используем технику типизации экземпляром объекта. В результате можем дальше отлично работать с полученным объектом:
Console.WriteLine("First = {0}, Last = {1}", beatle.First, beatle.Last);
Сама по себе техника очень интересна и может быть полезна, однако, перед тем как бросаться использовать эту технику для возвращения анонимных типов, подумайте - если у вас есть тип, который стоит повторно использовать в других методах, то почему бы не описать его как подобает и не использовать лишнего шаманства, имеющего тенденцию к снижению читаемости кода.
Листинг примера 1
using System;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
var beatlesMember = new { FirstName = "John",
LastName = "Lennon" };
var beatlesList =
(new[] { beatlesMember }).ToList();
beatles.Add(new { FirstName = "Paul",
LastName = "McCartney" });
beatles.Add(new { FirstName = "George",
LastName = "Harrison" });
beatles.Add(new { FirstName = "Ringo",
LastName = "Starr" });
foreach (var beatle in beatles)
{
Console.WriteLine(beatle.FirstName +
" " + beatle.LastName);
}
}
}
}
Листинг примера 2
using System;
namespace ConsoleApplication1
{
class Program
{
static object GetBeatleName() {
return new { First = "John", Last = "Lennon" }; }
static T CastType(object obj, T type) {
return (T)obj; }
static void Main()
{
object obj = GetBeatleName();
var beatle = CastType(obj, new { First = "",
Last = "" });
Console.WriteLine("First={0}, Last={1}",
beatle.First, beatle.Last);
}
}
}