2010-05-25 11 views
9

Estoy buscando implementar algunas formas más agradables de usar List en un par de aplicaciones en las que estoy trabajando. Mi implementación actual se ve así.¿Cuál es una forma mejor y más limpia de usar List <T>

MyPage.aspx.cs

protected void Page_Load(object sender, EventArgs e) 
{ 
    BLL.PostCollection oPost = new BLL.PostCollection(); 
    oPost.OpenRecent(); 
    rptPosts.DataSource = oArt; 
    rptPosts.DataBind(); 
} 

BLL Clase (s)

public class Post 
{ 
    public int PostId { get; set; } 
    public string PostTitle { get; set; } 
    public string PostContent { get; set; } 
    public string PostCreatedDate { get; set; } 

    public void OpenRecentInitFromRow(DataRow row) 
    { 
     this.PostId = (int) row["id"]; 
     this.PostTitle = (string) row["title"]; 
     this.PostContent = (string) row["content"]; 
     this.PostCreatedDate = (DateTime) row["createddate"]; 
    } 
} 
public class PostCollection : List<Post> 
{ 
    public void OpenRecent() 
    { 
     DataSet ds = DbProvider.Instance().Post_ListRecent(); 
     foreach (DataRow row in ds.Tables[0].Rows) 
     { 
      Post oPost = new Post(); 
      oPost.OpenRecentInitFromRow(row); 
      Add(oPost); 
     } 
    } 
} 

Ahora bien, aunque esto está funcionando muy bien, me pregunto si hay alguna manera de mejorar y hacer que sea más limpio que tener que usar las dos clases diferentes hace algo que creo que puede suceder en una sola clase o utilizando una interfaz.

+0

¿Hay alguna forma de que su capa DB devuelva algo que no sea una tabla (por ejemplo, usar un lector de datos para llenar su lista de objetos allí)? – Paddy

+2

Esto podría ser una preferencia personal, pero también eliminaría la notación húngara del código de la página. – Paddy

+0

@Paddy - ¡Estoy trabajando en eso! Solo lo uso para cosas como repetidores donde me ayuda a recordar. Pero todo está desapareciendo lentamente del código. –

Respuesta

17

Por un lado, no se derivaría de List<T> - usted no está realmente especializar el comportamiento.

También me gustaría sugerir que usted podría hacer Post inmutable (al menos externamente), y escribo un método estático (o constructor) para crear una basada en un DataRow:

public static Post FromDataRow(DataRow row) 

Del mismo modo se puede tener una método de lista:

public static List<Post> RecentPosts() 

que los devuelve. Es cierto que podría ser mejor como un métodoejemplo, en una especie de clase DAL, lo que permitirá burlarse etc. Por otra parte, en la publicación:

public static List<Post> ListFromDataSet(DataSet ds) 

Ahora, en cuanto al uso de List<T> sí mismo - está usando. NET 3.5? Si es así, usted podría hacer esto considerablemente más ordenado usando LINQ:

public static List<Post> ListFromDataSet(DataSet ds) 
{ 
    return ds.Tables[0].AsEnumerable() 
         .Select(row => Post.FromDataRow(row)) 
         .ToList(); 
} 
+7

+1 para "No derivar de la lista" - muy raramente, si alguna vez, quieres hacer eso. ** ¡Favorece la composición a la herencia! ** (Java efectivo, elemento 16)) –

+0

Ni siquiera hay necesidad de composición en este caso. –

+2

Además, específicamente no se deriva de la lista . En general, es mejor heredar la colección porque le da los métodos Agregar, Eliminar, etc., que puede anular – RichK

2

Editar: La respuesta de John Skeet es probablemente una mejor opción. Pero si quiere hacer solo unos pocos cambios simples, siga leyendo:

Coloque el código de acceso a la base de datos, OpenRecentInitFromRow en la PostCollection y trátelo como una clase de administrador de correos. De esa forma, la clase Post es un Objeto simple de Transferencia de Datos.

public class Post 
{ 
    public int PostId { get; set; } 
    public string PostTitle { get; set; } 
    public string PostContent { get; set; } 
    public string PostCreatedDate { get; set; } 
} 

public class PostCollection : List<Post> 
{ 
    public void OpenRecent() 
    { 
     DataSet ds = DbProvider.Instance().Post_ListRecent(); 
     foreach (DataRow row in ds.Tables[0].Rows) 
     { 
      Add(LoadPostFromRow(row)); 
     } 
    } 

    private Post LoadPostFromRow(DataRow row) 
    { 
     Post post = new Post(); 
     post.PostId = (int) row["id"]; 
     post.PostTitle = (string) row["title"]; 
     post.PostContent = (string) row["content"]; 
     post.PostCreatedDate = (DateTime) row["createddate"]; 
     return post; 
    } 
} 
+0

Me gusta la idea de esto. Pero al final estoy tratando de acabar con estas dos clases, donde en una bastaría. Además, nunca me ha gustado la clase 'PostCollection' que estoy usando. Creo que se ve feo, sin mencionar que estoy seguro de que hay altibajos de rendimiento en este enfoque ... bueno, tal vez, funciona bastante bien y tengo muchos de memoria y ciclos de reloj de sobra! –

0

usted puede hacer esto:

protected void Page_Load(object sender, EventArgs e) 
{ 
    BLL.PostCollection oPost = new BLL.PostCollection(); 
    rptPosts.DataSource = Post.OpenRecent(); 
    rptPosts.DataBind(); 
} 
public class Post 
{ 
    public int PostId { get; set; } 
    public string PostTitle { get; set; } 
    public string PostContent { get; set; } 
    public string PostCreatedDate { get; set; } 

    public void OpenRecentInitFromRow(DataRow row) 
    { 
     this.PostId = (int) row["id"]; 
     this.PostTitle = (string) row["title"]; 
     this.PostContent = (string) row["content"]; 
     this.PostCreatedDate = (DateTime) row["createddate"]; 
    } 

    public static List<Post> OpenRecent() 
    { 
     DataSet ds = DbProvider.Instance().Post_ListRecent(); 
     foreach (DataRow row in ds.Tables[0].Rows) 
     { 
      Post oPost = new Post(); 
      oPost.OpenRecentInitFromRow(row); 
      Add(oPost); //Not sure what this is doing 
     } 
     //need to return a List<Post> 
    } 
} 
2

¿Está derivados de Lista <T> porque quiere ofrecer otros consumidores de PostCollection la capacidad para agregar y quitar elementos? Supongo que no, y que en realidad solo quieres una forma de exponer una colección a la que puedas vincular. Si es así, usted podría considerar un iterador, tal vez:

class BLL { 
    ... 

    public IEnumerable<Post> RecentPosts { 
     get { 
      DataSet ds = DbProvider.Instance().Post_ListRecent(); 
      foreach (DataRow row in ds.Tables[0].Rows) 
      { 
       Post oPost = new Post(); 
       oPost.OpenRecentInitFromRow(row); 
       yield return oPost; 
      } 
     } 
    }  

    ... 
} 

A pesar de que esto podría ser considerado como la falta de forma (en la que tenemos una propiedad de captador que podrían estar haciendo una llamada a la red), este enfoque iterador hará de distancia con la sobrecarga de llamar a OpenRecentInitFromRow para las publicaciones que nunca se enumeran.

También se vuelve agnóstico sobre cómo los consumidores potenciales de sus publicaciones pueden querer consumirlas. El código que, de manera absoluta y positiva, tiene que tener cada publicación puede hacer ToList(), pero otro código podría querer usar una consulta LINQ que cortocircuite la enumeración después de que se encuentre la publicación correcta.

+0

Después de trabajar con otro 'IEnumerable <>' usando 'yield return xxx' me gusta mucho cómo funciona. En este momento, todavía necesito trabajar con todas las publicaciones para configurar el almacenamiento en caché y la paginación, pero lo volveré a visitar para otros conjuntos de datos en el futuro cercano. –

2

Estoy mirando para poner en práctica algunas de las formas más agradable de usar Lista

Eso parece una extraña petición. El tipo "Lista" es un medio, rara vez un final. Con eso en mente, una forma más agradable de lograr su verdadero objetivo es usar IEnumerable en lugar de List, porque esa lista lo obliga a mantener toda su colección en la memoria, mientras que IEnumerable solo requiere un objeto a la vez. El truco consiste en que debe conectar todo en la secuencia de procesamiento, desde la capa de datos hasta la presentación, para usarlo.

que tienen un buen ejemplo en el enlace de más abajo acerca de cómo hacer esto de una manera muy limpia:
Fastest method for SQL Server inserts, updates, selects

Dependiendo de su código de capa de datos existente que puede ser capaz de rozar la mayor parte de la primera mitad de la publicación (larga): el punto principal es que utiliza un bloque de iterador para convertir un SqlDataReader en IEnumerable<IDataRecord>. Una vez que tienes eso, es bastante sencillo el resto del camino.

+0

Gracias por los consejos, voy a ver esto también para otra aplicación que recién está empezando y quiero asegurarme de hacer lo mejor posible, ¡la primera vez! –

Cuestiones relacionadas