【问题标题】:What is a better, cleaner way of using List<T>使用 List<T> 的更好、更简洁的方法是什么
【发布时间】:2010-05-25 13:27:53
【问题描述】:

我希望在我正在开发的几个应用程序中实现一些更好的方法来使用 List。我当前的实现看起来像这样。

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 类

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);
        }
    }
}

现在虽然这一切都很好,但我只是想知道是否有任何方法可以改进它,并让它更清晰,因为必须使用两个不同的类来做一些我认为可以在一个中发生的事情类或使用接口。

【问题讨论】:

  • 有没有办法让你的 DB 层返回表格以外的东西(例如,使用数据读取器来填充你的对象列表)?
  • 这可能是个人喜好,但我也会从您的页面代码中删除匈牙利符号。
  • @Paddy - 我正在努力!我只将它用于一些可以帮助我记住的东西,例如中继器。但这一切都在慢慢从代码中剔除。

标签: c# list


【解决方案1】:

一方面,我不会从 List&lt;T&gt; 派生 - 你并没有真正专注于行为。

我还建议您可以使 Post 不可变(至少在外部),并编写一个静态方法(或构造函数)以基于 DataRow 创建一个:

public static Post FromDataRow(DataRow row)

同样你可以有一个列表方法:

public static List<Post> RecentPosts()

返回它们。诚然,作为某种 DAL 类中的 instance 方法可能会更好,这将允许模拟等。或者,在 Post 中:

public static List<Post> ListFromDataSet(DataSet ds)

现在,至于 List&lt;T&gt; 本身的使用 - 您使用的是 .NET 3.5 吗?如果是这样,您可以使用 LINQ 使这更加整洁:

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

【讨论】:

  • +1 表示“不要从列表中派生” - 如果有的话,您很少会这样做。 有利于继承的组合!(有效的 Java,第 16 条)
  • 在这种情况下甚至不需要作曲。
  • 另外,特别是不要从 List 派生。继承 Collection 通常会更好,因为它为您提供了可以覆盖的 Add、Remove 等方法
  • 嗯,看来我真的需要做一些工作来弄清楚如何实现这一点。我目前为此使用 3.5,所以我肯定会使用该 LINQ 方法,我只需要弄清楚如何让它们一起工作。
【解决方案2】:

您是否从 List 派生,因为您想为 PostCollection 的其他消费者提供添加和删除项目的能力?我猜不是,你实际上只是想要一种方法来公开你可以绑定的集合。如果是这样,您可以考虑使用迭代器,也许:

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;
            } 
        }
    }    

    ...
}

尽管这可能被认为是糟糕的形式(因为我们有一个可能进行网络调用的属性获取器),但这种迭代器方法将消除为从未枚举的帖子调用 OpenRecentInitFromRow 的开销。

您也变得不知道帖子的潜在消费者可能希望如何使用它们。绝对肯定必须让每个 Post 都可以执行 ToList() 的代码,但其他代码可能想要使用 LINQ 查询,以便在找到正确的 Post 后使枚举短路。

【讨论】:

  • 在使用yield return xxx 与另一个IEnumerable&lt;&gt; 合作后,我真的很喜欢它的工作方式。目前我仍然需要处理所有帖子以设置一些缓存和分页,但我会在不久的将来重新访问它以用于其他一些数据集。
【解决方案3】:

编辑:John Skeet 的回答可能是一个更好的选择。但是,如果您只想进行一些简单的更改,请继续阅读:

将数据库访问代码 OpenRecentInitFromRow 放入 PostCollection 并将其视为 Post 管理器类。这样 Post 类就是一个普通的旧数据传输对象。

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;
    }
}

【讨论】:

  • 我喜欢这个主意。但最后,我试图取消这两个课程,而这两个课程合二为一。此外,我从不喜欢我正在使用的PostCollection 类,我认为它看起来很难看,更不用说我敢肯定这种方法会产生性能开销......好吧,也许它工作得很好而且我有很多内存和时钟周期空闲!!
【解决方案4】:

我正在寻找一些更好的方法来使用 List

这似乎是一个奇怪的要求。 “列表”类型是一种手段,很少是目的。考虑到这一点,实现真正目的的一种更好的方法是使用 IEnumerable 而不是 List,因为 List 会强制您将整个集合保存在内存中,而 IEnumerable 一次只需要一个对象。诀窍是您必须在处理流中连接所有内容,从数据层一直到表示,才能使用它。

我在下面的链接中有一个很好的例子,说明如何以非常干净的方式做到这一点:
Fastest method for SQL Server inserts, updates, selects

根据您现有的数据层代码,您可能可以略读(长)帖子的前半部分的大部分内容 - 要点是您使用迭代器块将 SqlDataReader 转换为 IEnumerable&lt;IDataRecord&gt;。一旦你有了它,接下来的过程就非常简单了。

【讨论】:

  • 感谢您的提示,我也会关注这个以及另一个刚刚开始的应用程序,我想确保尽可能做到最好,第一次!
【解决方案5】:

你可以这样做:

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>
    }
}

【讨论】:

    猜你喜欢
    • 2011-01-20
    • 1970-01-01
    • 1970-01-01
    • 2012-05-08
    • 2016-11-09
    • 2011-10-30
    • 2014-05-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多