Игра с анонимными типами - PullRequest
9 голосов
/ 15 июля 2010

Из замечательной книги Джона Скита C # In Depth, First Edition :

class Film
{
    public string Name { get; set; }
    public int Year { get; set; }

    public override string ToString()
    {
        return string.Format("Name={0}, Year={1}", Name, Year);
    }
}

var films = new List<Film>
{
    new Film {Name="Jaws", Year=1975},
    new Film {Name="Singing in the Rain", Year=1952},
    new Film {Name="Some Like It Hot", Year=1959},
    new Film {Name="The Wizard of Oz", Year=1939},
    new Film {Name="It's a Wonderful Life", Year=1946},
    new Film {Name="American Beauty", Year=1999},
    new Film {Name="High Fidelity", Year=2000},
    new Film {Name="The Usual Suspects", Year=1995}
};

Action<Film> print = film => { Console.WriteLine(film); };
films.ForEach(print);
films.FindAll(film => film.Year < 1960)
.ForEach(print);
films.Sort((f1, f2) => f1.Name.CompareTo(f2.Name));
films.ForEach(print);

Абзац следует за приведенным выше фрагментом кода.

Первая половина листинга 9.4 связана с настройкой данных.Я бы использовал анонимный тип, но довольно сложно создать общий список из коллекции экземпляров анонимного типа.(Это можно сделать, создав общий метод, который принимает массив и преобразует его в список того же типа, а затем передает в этот метод неявно типизированный массив. Метод расширения в .NET 3.5, называемый ToListпредоставляет и эту функциональность, но это было бы обманом, так как мы еще не рассматривали методы расширения!)

А фрагмент кода, приведенный выше, перечисляет 9.4 книги, на которую ссылается абзац.

Мой вопрос: Я пробую технику, описанную в предыдущем абзаце, от руки (посмотрите на выделенный курсивом текст), но я не совсем понимаю, что он имеет в виду.

Я попробовал что-то подобное, но, я полагаю, это не то, что он имел в виду, поскольку это не работает (и я не ожидал, что это произойдет):

using System;
using System.Collections.Generic;

namespace ScratchPad
{

class Film
{
    public string Name { get; set; }
    public int Year { get; set; }

    public override string ToString()
    {
        return string.Format("Name = {0}\tYear = {1}", 
            Name, Year);
    }
}

class Program
{
    static void Main(string[] args)
    {
        ToList<Film>( new[]
        {
            new { Name = "North By Northwest", Year = 1959 },
            new { Name = "The Green Mile", Year = 1999},
            new { Name = "The Pursuit of Happyness", Year = 2006}
        }).ForEach( f => {Console.WriteLine(f);} );

        Console.ReadKey();
    }

    static List<T> ToList<T>(
        System.Collections.IEnumerable list)
    {
        var newList = new List<T>();

        foreach (var thing in list)
            if (thing is T)
                newList.Add((T)thing);

        return newList;

    }
}

}

Примечание: Я знаю о методе расширения IEnumerable.ToList () и использовал его много раз.Я просто хочу попробовать технику, описанную в этом абзаце, вручную.

Кроме того, я заинтригован сценариями, в которых анонимные типы используются за пределами Linq, в качестве синтаксического удобства, и один из таких сценариев приведен ниже.Я всегда могу использовать dynamic в C # 4 и принимать анонимный тип в качестве аргумента и работать с ним, зная, чего я ожидаю.Я хотел бы сделать это с C # 3. Что-то вроде ниже:

using System;
using Microsoft.CSharp.RuntimeBinder;

namespace PlayWithAnonType
{
    class Program
    {
        static void Main(string[] args)
        {
            PrintThingy(new { Name = "The Secret", 
Genre = "Documentary", Year = 2006 });
            Console.ReadKey();
        }

    static void PrintWhatever(dynamic whatever)
    {
        // the anonymous type's ToString() will print
        Console.WriteLine(whatever);
    }

    static void PrintThingy(dynamic thingy)
    {
        try
        {
            // I know what the thingy is
            Console.WriteLine("Name = {0}\tGenre = {1}\tYear = {2}",
                thingy.Name, thingy.Genre, thingy.Year);
        }
        catch(RuntimeBinderException ex)
        {
#pragma warning disable 0168
            Console.WriteLine("By thingy, I really meant film. 
Sorry, I should've clarified.");
#pragma warning restore 0168
        }
    }
}

}

Edit У них должен быть тег с именем jon-skeet.

Ответы [ 3 ]

8 голосов
/ 15 июля 2010

Дело в том, что если бы мы знали о ToList, у нас был бы способ создать список, не имея вообще собственного типа Film. Не то чтобы мы могли смешивать анонимный тип с типом Film. Другими словами, мы могли бы сделать:

// The type of list will be List<T> where T is the anonymous type
var list = new[]
{
    new { Name = "North By Northwest", Year = 1959 },
    new { Name = "The Green Mile", Year = 1999},
    new { Name = "The Pursuit of Happyness", Year = 2006}
}.ToList();

list.ForEach(x => Console.WriteLine("{0} ({1})", x.Name, x.Year));

Рад, что вы наслаждаетесь первым изданием, кстати - надеюсь, скоро второе издание выйдет:)

6 голосов
/ 15 июля 2010

Чтобы на самом деле это сделать:

public void Main (string[] args)
{
    var films = ToList(new [] {
        new {Name = "Jaws", Year = 1975},
        new {Name = "Singing in the Rain", Year = 1952},
        new {Name = "Some Like It Hot", Year = 1959},
        new {Name = "The Wizard of Oz", Year = 1939},
        new {Name = "It's a Wonderful Life", Year = 1946},
        new {Name = "American Beauty", Year = 1999},
        new {Name = "High Fidelity", Year = 2000},
        new {Name = "The Usual Suspects", Year = 1995}
    }
    );


    films.ForEach(f => Console.Write(f.Name + " - " + f.Year));

}

public List<T> ToList<T> (IEnumerable<T> list)
{
    return new List<T>(list);
}

Как уже упоминали другие, я не уверен, насколько это полезно. Вы получаете intellisense и все такое, когда вы пишете это, так что, вероятно, есть некоторая экономия при наборе, по крайней мере? :)

4 голосов
/ 15 июля 2010

Я не думаю, что то, что описывает Джон, на самом деле очень полезно для вас здесь. Единственное, о чем он говорит, это то, что он обычно не создавал бы целый класс Film только для этого примера, если бы не проблемы с созданием List<AnonType>.

Редактировать: Черт. Хорошо, на этот раз я оставляю здесь свой ответ в любом случае:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...