using System;
using System.Collections.Generic;
using System.Linq;
class Program {
class Employee {
public string Name { get; set; }
public string City { get; set; }
public int Salary { get; set; }
}
static List<Employee> Staff() {
return new List<Employee> {
new Employee { Name = "Ann", City = "Rome", Salary = 90 },
new Employee { Name = "Bob", City = "Paris", Salary = 70 },
new Employee { Name = "Cid", City = "Rome", Salary = 50 }
};
}
// *** before: ***
// selecting, sorting and collecting were written by hand every time,
// and the intent drowned in the loops
static List<string> RichInRomeOld(List<Employee> staff) {
List<Employee> found = new List<Employee>();
foreach (Employee e in staff)
if (e.City == "Rome" && e.Salary > 60) found.Add(e);
found.Sort(delegate(Employee a, Employee b) { return b.Salary -
a.Salary; });
List<string> names = new List<string>();
foreach (Employee e in found) names.Add(e.Name);
return names;
}
// *** in version 3.0: ***
// a query is part of the language, and the compiler checks the names
static IEnumerable<string> RichInRomeNew(List<Employee> staff) {
return from e in staff
where e.City == "Rome" && e.Salary > 60
orderby e.Salary descending
select e.Name;
}
static void Main() {
List<Employee> staff = Staff();
Console.WriteLine(string.Join(", ", RichInRomeOld(staff).ToArray()));
Console.WriteLine(string.Join(", ", RichInRomeNew(staff).ToArray()));
// grouping and totals speak the same language
var byCity = from e in staff
group e by e.City into g
select new { City = g.Key, Total = g.Sum(e => e.Salary) };
foreach (var row in byCity)
Console.WriteLine(row.City + " " + row.Total);
// the query is only built here and runs at the first read of it
var query = from e in staff where e.Salary > 60 select e.Name;
staff.Add(new Employee { Name = "Dee", City = "Rome", Salary = 95 });
Console.WriteLine(query.Count()); // 3: Dee is counted too
}
}