【问题标题】:Why is my C# Array changing without anything being assigned to it?为什么我的 C# 数组在没有分配任何内容的情况下发生变化?
【发布时间】:2020-06-29 18:27:03
【问题描述】:

我有一个小型 winforms 程序,用于创建食谱书。该应用程序有两个窗口,但我的错误只与一个有关。

我有两个主要的类:Recipe.cs 和RecipeManager.cs,其想法是RecipeManager 包含一个Recipes 数组。 (对于这个任务,我们不允许使用 Linq 或 ArrayLists)

现在,当我填写表格并单击“添加配方”时,第一个成功运行并且列表框正确填充,但是第二次“添加配方”recipeList 数组似乎被新的完全食谱,我不知道为什么会这样。 recipeList 似乎在我的 Add 方法甚至将它添加到数组之前发生了变化!

查看相关问题的 gif:

https://i.imgur.com/sIMICcG.gifv

食谱.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace programmingTask4
{
    public class Recipe
    {
        private string[] ingredientArray;
        private string name;
        private FoodCategory category;
        private string description;
        private const int maxNumOfIngredients = 20;

       public string Name
        {
            get { return name; }
            set { name = value; }
        }
        public FoodCategory Category
        {
            get { return category; }
            set { category = value; }
        }
        public string Description
        {
            get { return description; }
            set { description = value; }
        }
        public string[] Ingredient
        {
            get { return ingredientArray; }
            set { ingredientArray = value; }
        }
        public int MaxNumOfIngredients
        {
            get { return ingredientArray.Length; }
        }

        public Recipe(int maxNumOfIngredients)
        {
            Console.WriteLine("Recipe constructor was called!");
            ingredientArray = new string[maxNumOfIngredients];
            DefaultValues();
        }
        public void DefaultValues()
        {
            for (int i = 0; i < ingredientArray.Length; i++)
            {
                ingredientArray[i] = string.Empty;
                name = string.Empty;
                category = FoodCategory.Vegetarian;
                description = string.Empty;
            }
        }
        public int FindVacantPosition()
        {
            int results;
            for (int i = 0; i < ingredientArray.Length; i++)
            {
                if(ingredientArray[i] == string.Empty)
                {
                    results = i;
                    return results;
                }
            }
            return -1;
        }
        public bool AddIngredient(string value)
        {
            bool ok;
            int next = FindVacantPosition();
            if(next >= 0)
            {
                ok = true;
                ingredientArray[next] = value;
            }
            else { 
            ok = false ;
            }
            return ok;
        }
        public bool CheckIndex(int index)
        {
            bool check = false;
            if(index <= ingredientArray.Length && index >= 0)
            {
                check = true;
            }
            return check;
        }
        public int GetCurrentNumOfIngredients()
        {
            int count = 0;
            for (int i = 0; i < ingredientArray.Length; i++)
            {
                if (!string.IsNullOrEmpty(ingredientArray[i]))
                {
                    count++;
                }
            }
            return count;
        }
        public override string ToString()
        {
            int chars = Math.Min(description.Length, 15);
            string descriptionText = description.Substring(0, chars);

            if (string.IsNullOrEmpty(descriptionText))
                descriptionText = "NO DESCRIPTION";

            string textOut = string.Format("{0, -20} {1,4} {2,-12} {3,-15}", name, GetCurrentNumOfIngredients(), category.ToString(), descriptionText);
            return textOut;
        }
        public bool ChangeIngredientAt(int index, string value)
        {
            bool bok = true;
            if (CheckIndex(index))
                ingredientArray[index] = value;
            else
                bok = false;
            return bok;
        }
        public bool DeleteIngredientAt(int index)
        {
            bool bok = true;
            if (CheckIndex(index))
                ingredientArray[index] = "NO DESCRIPTION";
            else
                bok = false;
            return bok;
        }


    }
}

RecipeManager.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace programmingTask1
{
    class RecipeManager
    {
        private Recipe[] recipeList;

        public RecipeManager(int maxNumOfElements)
        {
            Console.WriteLine("Recipe manager constructor called!");
            recipeList = new Recipe[maxNumOfElements];
        }

        private int FindVacantPosition()
        {
            for (int i = 0; i < recipeList.Length; i++)
            {
                if (recipeList[i] == null)
                {
                    Console.WriteLine("Found free position at: " + i);
                    return i;
                }

            }
            return -1;
        }
        public bool CheckIndex(int index)
        {
            bool check = false;
            if (index <= recipeList.Length && index >= 0)
            {
                check = true;
            }
            return check;
        }
        public Recipe GetRecipeAt(int index)
        {
            if (CheckIndex(index))
                return recipeList[index];
            else
                return null;
        }
        public bool Add(Recipe newRecipe)
        {
            if (newRecipe == null)
                return false;

            bool ok;
            int next = FindVacantPosition();
            if (next >= 0)
            {
                ok = true;
                Console.WriteLine("Setting recipe list at index " + next + " to " + newRecipe.ToString());
                recipeList[next] = newRecipe;

            }
            else
            {
                Console.WriteLine("No space for recipe available! " + next);
                ok = false;
            }
            return ok;
        }

        public int CurrentNumberofItems()
        {
            int num = 0;
            for (int i = 0; i < recipeList.Length; i++)
            {
                if (recipeList[i] != null)
                {
                    num++;
                }
            }
            return num;
        }
        public string[] RecipeListToString()
        {
            string[] results = new string[recipeList.Length];
            for (int i = 0; i < recipeList.Length; i++)
            {
                if (recipeList[i] != null)
                    results[i] = recipeList[i].ToString();
                else
                    results[i] = string.Empty;
            }
            return results;
        }
    }
}

FormMain.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace programmingTask4
{
    public partial class FormMain : Form
    {
        const int maxRecipe = 3;
        const int maxIngredients = 20;
        Recipe currRecipe = new Recipe(maxIngredients);
        RecipeManager recipemanager = new RecipeManager(maxRecipe);

        public FormMain()
        {
            Console.WriteLine("Form constructor was called!");
            InitializeComponent();
            InitializeGui();
        }

        public void InitializeGui()
        {
            comboBoxCategory.DataSource = Enum.GetValues(typeof(FoodCategory));
        }
        public void UpdateGUI()
        {
            //listBoxDisplay.Text = recipemanager.CurrentNumberofItems().ToString();
            //listBoxDisplay.Text = currRecipe.Ingredient.ToString();

            string[] recipeListStrings = recipemanager.RecipeListToString();
            listBoxDisplay.Items.Clear();
            listBoxDisplay.Items.AddRange(recipeListStrings);
        }

        private void buttonRecipe_Click(object sender, EventArgs e)//add recipe button
        {
            currRecipe.Category = (FoodCategory)comboBoxCategory.SelectedIndex;
            currRecipe.Name = textBoxRecipeName.Text.Trim();
            currRecipe.Description = richTextBoxDescription.Text.Trim();

            Console.WriteLine("Adding recipe: " + currRecipe.ToString());
            bool result = recipemanager.Add(currRecipe);
            Console.WriteLine("Result was " + result + " for adding to recipe list");
            UpdateGUI();

            currRecipe.DefaultValues();   
        }
    }
}

【问题讨论】:

  • Using the free, built-in Step Debugger 调试代码比您想象的要容易。它还将帮助您了解代码的执行方式,从而帮助您编写更好的代码。
  • 我在我的代码中添加了断点,然后慢慢地通过(并进入)。只要调用 Add ,但在 Add 有机会做任何事情之前,recipeList 就会发生变化。 @ŇɏssaPøngjǣrdenlarp
  • 一方面,你让它变得比它需要的更复杂。数据绑定将简化显示方面,并且现代集合已经提供了您复制到查找和检查事物的所有功能。此外,您不会在调用 Add 的单击事件中创建新的配方项。然后更新道具的行正在更改最后一项并再次添加它
  • @Cherona 研究一下reference type,你会明白的。

标签: c# arrays winforms class


【解决方案1】:
  1. Recipe 是一个类,这意味着它是一个 reference type.
  2. 在您的主窗体中,您的 currRecipe 实例永远不会更改。
  3. RecipeManager 有一个数组来存储实例的引用,但不幸的是它存储了相同的实例,因为 2。
  4. 由于RecipeManager 存储了currRecipe 的同一个实例,因此对currRecipe 的任何修改都会显示N 次。

为了防止它。修改你的buttonRecipe_Click

    private void buttonRecipe_Click(object sender, EventArgs e)//add recipe button
    {
        currRecipt = new Recipe(maxIngredients);
        currRecipe.Category = (FoodCategory)comboBoxCategory.SelectedIndex;
        currRecipe.Name = textBoxRecipeName.Text.Trim();
        currRecipe.Description = richTextBoxDescription.Text.Trim();

        Console.WriteLine("Adding recipe: " + currRecipe.ToString());
        bool result = recipemanager.Add(currRecipe);
        Console.WriteLine("Result was " + result + " for adding to recipe list");
        UpdateGUI();

        // No need to reset it, use new one everytime.
        //currRecipe.DefaultValues();   
    }

【讨论】:

    猜你喜欢
    • 2020-11-10
    • 2014-06-22
    • 2015-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-05
    • 2015-08-11
    • 1970-01-01
    相关资源
    最近更新 更多