From Jon Skeet's wonderful book 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);
A paragraph follows the above-listed snippet of code.
The first half of listing 9.4 involves just setting up the data. I would have used an anonymous type, but it’s relatively tricky to create a generic list from a collection of anonymous type instances. (You can do it by creating a generic method that takes an array and converts it to a list of the same type, then pass an implicitly typed array into that method. An extension method in .NET 3.5 called ToList provides this functionality too, but that would be cheating as we haven’t looked at extension methods yet!)
And the code snippet provided above, is listing 9.4 of the book that the paragraph refers to.
My question: I am trying out the technique outlined in the above paragraph by hand (look at the italicized text) but I can't quite understand what he means.
I tried something like this but it isn't what he meant, I suppose, as it doesn't work (and I didn't expect it to):
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;
}
}
}
Note: I know about the IEnumerable.ToList() extension method and have used it many times. I just want to try the technique outlined in the paragraph by hand.
Also, I'm intrigued by scenarios where anonymous types are used outside of Linq, as a syntactic convenience and one of such scenarios is given below. I can always use dynamic
in C# 4 and accept an anonymous type as an argument and work with it knowing what I expect. I wish I could do that with C# 3. Something like below:
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 They should have a tag named jon-skeet.
Anonymous types typically are used in the select clause of a query expression to return a subset of the properties from each object in the source sequence. For more information about queries, see LINQ in C#. Anonymous types contain one or more public read-only properties.
Essentially an anonymous type is a reference type and can be defined using the var keyword. You can have one or more properties in an anonymous type but all of them are read-only. In contrast to a C# class, an anonymous type cannot have a field or a method — it can only have properties.
The point was that if we knew about ToList
we'd have a way of creating the list without having our own Film
type at all. It wasn't that we'd be able to mix an anonymous type with a Film
type. In other words, we could do:
// 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));
Glad you're enjoying the first edition, btw - hopefully it won't be too long before the second edition comes out :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With