【问题标题】:Looping to Create and Add New Objects to ArrayList循环创建新对象并将其添加到 ArrayList
【发布时间】:2016-01-11 16:41:38
【问题描述】:

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

我正在尝试创建和填充博客对象的 ArrayList。我确实知道这样做的通用方法:

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

正如我之前所说,这样做的结果是一个 ArrayList,其中包含指向 Kristina_Blogs 表中最后一个博客的指针。我想 ArrayList allBlogs 看起来像 [b, b, b, ... b] ,因此当我说 b.setTitle() 等时它们都会更新。但是如果我正在创建一个新的 Blog 对象怎么会是这样在每次迭代开始时?


以下是一些您不必阅读的额外信息,但它可能会消除对问题结构的一些混淆:

  1. 博客对象具有 id、title 和 message 字段及其各自的 getter/setter
  2. Kristina_Blogs 是一个表格,表示这些博客,其中包含 id、title、message 列
  3. 建议为我的数据库引擎添加一个标签,但我找不到它的标签:Microsoft SQL Server Management Studio
  4. 当我使用字符串的 ArrayList 而不是博客时,此代码可以完美运行

编辑:包括来自博客类的代码

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

}

【问题讨论】:

  • 不回答您的问题,但考虑使用 List 而不是 ArrayList。 ArrayList 是泛型和类型化集合之前的选择(如果我没记错的话,从 .Net 2 开始)
  • 最好分享您的Blog 代码。我想问题在于您的 Blog 类具有静态成员变量。
  • 另外最好使用属性来设置值,而不是setXsetY
  • @RezaAghaei 我将添加我的博客代码。你是对的,这些字段都是静态的。您能否解释一下您所说的“使用属性设置值”是什么意思?
  • @Kristina 是的,我会为您发布答案。请更新您的问题并添加您的课程代码。

标签: c# sql arraylist


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      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 关键字,您允许对象的不同实例保存不同的值。

      现在,每次创建博客对象时,该对象的标题和消息等都会包含其自己的信息。

      【讨论】:

      • 哦,好的,谢谢。我不知道为什么我首先制作了这些静态文件,但现在一切正常。如果我希望所有博客都链接到同一个应用程序,我应该将 myApp 字段设为静态吗?
      • 当然,但是如果您更改一个博客的 App 变量,那么它会更改为所有博客。
      【解决方案4】:

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

          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”是整数。还可以考虑将“博客”对象的创建移到循环之外并只更改值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-11-04
        • 2016-01-05
        • 1970-01-01
        • 2016-03-17
        • 1970-01-01
        • 2016-07-20
        • 1970-01-01
        相关资源
        最近更新 更多