Трюки с анонимными типами


Пусть читатели еще немного поломают ломают голову над задачками из предыдущего поста - свои ответы я опубликую еще через неделю. Хотя, должен отметить, читатели просто молодцы и отлично справляются с решением задачек. А я тем временем опубликую оставшуюся часть материала презентации на SECR.


Представим себе ситуацию, что в мы создали некоторый метод в котором хотели бы использовать список анонимных типов. Например, описываемых вот так:


var beatleJohn = new { FirstName = "John", LastName = "Lennon" };


При этом мы хотим сохранить строгую типизацию списка, поэтому логичным видится использование обобщенного класса List<T>. Однако, возникает вопрос, как нам чисто синтаксически создать обобщенный список не зная имени типа - фактически для нас анонимные типы, как и следует из названия, являются безымянными. Тут нужно вспомнить о технике создания обобщенной коллекции по экземпляру типа элемента коллекции.


Использование этого метода может выглядеть так:


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<T>(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<T>(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);
        }
    }
}

Comments (4)
  1. Hollander says:

    Господи, за такие трюки не худо бы руки поразбивать молотком по локоть.

  2. Denis says:

    Да что тут сказать – ЖЭСТЬ! А в целом весьма интересно и познавательно, хотя соглашусь с автором статьи в выводе и с автором предыдущего поста – практическое применение такого скорее исключение чем правило.

  3. int19h says:

    То ли еще будет с dynamic в C# 4.0 🙂

  4. Hankir says:

    Чудно всё это. Хотя бы для развития смекалки 🙂

    Лично мне приходилось несколько раз использовать анонимные типы. Остался, весьма, доволен результатом и эстетикой кода тоже.

Comments are closed.

Skip to main content