循环创建和添加新对象到ArrayList

本文关键字:对象 ArrayList 创建 添加 新对象 循环 | 更新日期: 2023-09-27 18:17:27

编辑以节省阅读整篇文章的时间tldr:对象的字段不应该是静态的,除非您希望该对象的所有实例对该字段具有相同的值

我正在尝试创建和填充博客对象的数组列表。我知道一般的做法:

create ArrayList of Blogs
loop (some condition)
     create new Blog
     add this Blog to AL

然而,当我尝试在while(datareader.read())循环中这样做时,ArrayList中的所有元素都是完全相同的Blog。具体来说,我最终得到了一个ArrayList,其中充满了指向数据库表中最后一个Blog对象的多个指针。下面是我的代码:

 public static ArrayList AllBlogs()
    {
        SqlDataReader dr = anonPage.ExecuteReader("SELECT * FROM Kristina_Blogs");
        ArrayList allBlogs = new ArrayList();
        if (dr.HasRows)
        {
            while (dr.Read())
            {
                Blog b = new Blog();
                //grab a row from Kristina_Blogs and assign those attributes to b
                b.setTitle(dr["title"].ToString());
                b.setMessage(dr["message"].ToString());
                b.setId(dr["id"]);
                allBlogs.Add(b);
            }
        }
        dr.Close();
        return allBlogs;
    }

就像我之前说的,结果是一个数组列表,里面充满了指向Kristina_Blogs表中最后一个博客的指针。我想象数组列表allBlogs看起来像[b, b, b,…]因此,当我说b时,它们都得到更新。settitle()等。但是,如果我在每次迭代开始时创建NEW Blog对象,怎么可能出现这种情况呢?


这里有一些额外的信息,你不需要阅读,但它可能会澄清一些关于问题结构的困惑:

  1. Blog对象有id、title和message字段以及它们各自的getter/setter
  2. Kristina_Blogs是一个表示这些博客的表,其中包含id、标题、消息
  3. 的建议说,包括一个标签为我的DB引擎,但我找不到一个标签:Microsoft SQL Server Management Studio
  4. 当我使用字符串数组列表而不是Blogs
  5. 时,这段代码可以完美地工作
编辑:包括来自Blog类的代码
public class Blog
{
    public App myApp;
    public static string Title;
    public static string Message;
    public static int Id;
    //constructors
    public Blog() { }
    public Blog(App App) { this.myApp = App; }
    //all getters and setters look like this
    public string getTitle() { return Title; }
    public void setTitle(string t) { Title = t; }
}

循环创建和添加新对象到ArrayList

正如我在评论中提到的,您的主要问题是您的成员变量是静态的,因此当您设置值时,它们在所有实例中都会更改。你应该这样修改你的代码:

public class Blog
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Message { get; set; }
}

并以这种方式填写您的列表,不要忘记添加using System.Linq;:

var result = new List<Blog>();
var connection = @"your connection string";
var command = "SELECT * FROM Kristina_Blogs";
var adapter = new System.Data.SqlClient.SqlDataAdapter(command, connection);
var dataTable = new DataTable();
//Get data
adapter.Fill(dataTable);
dataTable.Rows.Cast<DataRow>().ToList()
            .ForEach(row =>
            {
                var b = new Blog();
                b.Id = row.Field<int>("Id");
                b.Title = row.Field<string>("Title");
                b.Message = row.Field<string>("Message");
                result.Add(b);
            });
return result;

注意:

    创建成员static时,该成员在该类的所有实例之间共享。
  • 在c#中,你可以使用property来获取或设置值,你不需要setXsetY,当你获得属性的值时,该属性的get代码将执行,当你给属性赋值时,set部分将执行。你可以这样定义属性:

属性:

private int id;
public int Id
{
    get
    {
        return id;
    }
    set
    {
        id = value;
    }
}

或更简单:

public int Id { get; set; }

Blog类中的所有字段都是静态的,这意味着它们在所有对象实例之间共享。您希望它们是实例字段(即不是static),以便每个对象都有每个值的自己的副本。

从你的类中移除静态属性:

public class Blog
{
   public App myApp;
   public String Title;
   public String Message;
   public int Id;
//constructors
public Blog() { }
public Blog(App App) { this.myApp = App; }
//all getters and setters look like this
public String getTitle() { return Title; }
public String getMessage() { return Message; }
public void setTitle(String t) { Title = t; }
public void setMessage(String m) { Message = m; }    
}

当您使用static变量时,对象的所有实例将在这些变量中包含相同的值。通过删除static关键字,您允许对象的不同实例保存不同的值。

现在,每次你创建一个blog对象,该对象的Title和Message等,将包含它自己的信息

我会做一个快速的方法来防止null值抛出错误

    public static string GetSafeString(SqlDataReader reader, int index)
    {
        if (!reader.IsDBNull(index))
            return reader.GetString(index);
        else
            return string.Empty;
    }

替换此代码:

        while (dr.Read())
        {
            Blog b = new Blog();
            //grab a row from Kristina_Blogs and assign those attributes to b
            b.setTitle(dr["title"].ToString());
            b.setMessage(dr["message"].ToString());
            b.setId(dr["id"]);
            allBlogs.Add(b);
        }

与此代码:

         while (dr.Read())
        {
            Blog b = new Blog();
            //grab a row from Kristina_Blogs and assign those attributes to b
            b.setId(dr.GetInt32(0));
            b.setTitle(GetSafeString(dr, 1);
            b.setMessage(GetSafeString(dr, 2);
            allBlogs.Add(b);
        }

其中数字是记录中字段的索引,假设"id"是一个整数。还可以考虑将"Blog"对象的创建移到循环之外,只更改值。