循环创建和添加新对象到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对象,怎么可能出现这种情况呢?
这里有一些额外的信息,你不需要阅读,但它可能会澄清一些关于问题结构的困惑:
- Blog对象有id、title和message字段以及它们各自的getter/setter
- Kristina_Blogs是一个表示这些博客的表,其中包含id、标题、消息
- 的建议说,包括一个标签为我的DB引擎,但我找不到一个标签:Microsoft SQL Server Management Studio
- 当我使用字符串数组列表而不是Blogs 时,这段代码可以完美地工作
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; }
}
正如我在评论中提到的,您的主要问题是您的成员变量是静态的,因此当您设置值时,它们在所有实例中都会更改。你应该这样修改你的代码:
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;
注意:
- 创建成员
- 在c#中,你可以使用
property
来获取或设置值,你不需要setX
或setY
,当你获得属性的值时,该属性的get
代码将执行,当你给属性赋值时,set
部分将执行。你可以这样定义属性:
static
时,该成员在该类的所有实例之间共享。属性:
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"对象的创建移到循环之外,只更改值。