Changes in new versions / C# 3.0

using System;
using System.Collections.Generic;
using System.Linq;

class Program {
    class Employee {
        public string Name { getset; }
        public string City { getset; }
        public int Salary { getset; }
    }

    static List<EmployeeStaff() {
        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<stringRichInRomeOld(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<stringRichInRomeNew(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
    }
}