来自Jon Skeet的精彩书籍 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之外使用匿名类型的场景很感兴趣,因为语法方便,下面给出了其中一种场景。我总是可以在C#4中使用dynamic
并接受匿名类型作为参数,并在知道我期望的情况下使用它。我希望我能用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
}
}
}
}
修改 他们应该有一个名为jon-skeet的标签。
答案 0 :(得分:8)
关键在于,如果我们知道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));
很高兴你喜欢第一版,顺便说一句 - 希望在第二版出版之前不会太久:)
答案 1 :(得分:6)
实际做到这一点:
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和所有这些,所以至少可以节省一些打字费用吗? :)
答案 2 :(得分:4)
我不认为Jon在描述的内容对你来说实际上非常有用。他要做的唯一一点就是,如果没有创建Film
的问题,他通常不会为此示例创建整个班级List<AnonType>
。
编辑:该死的。好的,这次我还是在这里留下我的答案:)