tipos - return dynamic type c#
Jugando con tipos anĂ³nimos (3)
Del maravilloso libro de Jon Skeet, C # In Depth, Primera edición :
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);
Un párrafo sigue al fragmento de código mencionado anteriormente.
La primera mitad de la lista 9.4 implica simplemente configurar los datos. Hubiera usado un tipo anónimo, pero es relativamente complicado crear una lista genérica a partir de una colección de instancias de tipo anónimo. (Puede hacerlo creando un método genérico que tome una matriz y la convierta en una lista del mismo tipo, luego pase una matriz implícitamente tipada a ese método. Un método de extensión en .NET 3.5 llamado ToList proporciona también esta funcionalidad, pero eso sería una trampa ya que aún no hemos analizado los métodos de extensión).
Y el fragmento de código proporcionado anteriormente, está enumerando 9.4 del libro al que se refiere el párrafo.
Mi pregunta: estoy probando la técnica delineada en el párrafo anterior a mano (mire el texto en cursiva) pero no entiendo muy bien a qué se refiere.
Intenté algo así, pero supongo que no es lo que quiso decir, ya que no funciona (y no esperaba):
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;
}
}
}
Nota: Conozco el método de extensión IEnumerable.ToList () y lo he usado muchas veces. Solo quiero probar la técnica delineada en el párrafo a mano.
Además, me intrigan los escenarios en los que se usan tipos anónimos fuera de Linq, como una conveniencia sintáctica y uno de estos escenarios se detalla a continuación. Siempre puedo usar la dynamic
en C # 4 y aceptar un tipo anónimo como argumento y trabajar con él sabiendo lo que espero. Desearía poder hacer eso con C # 3. Algo como a continuación:
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
}
}
}
}
Editar Deben tener una etiqueta llamada jon-skeet.
El punto era que si supiéramos sobre ToList
tendremos una manera de crear la lista sin tener nuestro propio tipo de Film
. No es que pudiéramos mezclar un tipo anónimo con un tipo de Film
. En otras palabras, podríamos hacer:
// 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));
Me alegro de que estés disfrutando de la primera edición, por cierto, espero que no pase mucho tiempo antes de que salga la segunda edición :)
No creo que lo que Jon está describiendo sea realmente muy útil para ti aquí. El único punto que está haciendo es que normalmente no crearía una Film
clase completa solo para este ejemplo, si no fuera por los problemas con la creación de List<AnonType>
.
Editar: Maldición. De acuerdo, esta vez dejo mi respuesta aquí de todos modos :)
Para hacerlo realmente:
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);
}
Como otros han mencionado, no estoy seguro de lo útil que es esto. ¿Obtienes intellisense y todo eso cuando lo escribes, por lo que probablemente haya algunos ahorros de tipeo, al menos? :)