如何在 C# 中正确地将一个数组添加到另一个数组?

How to properly add an array to another array in C#?

我正在 Windows 的学校项目中进行动物登记。我有一个 Animal class,其中使用属性 Id、Name、Age、Gender 和 Friendly 创建动物对象。我还有一个处理列表的 AnimalManager class,通过它可以添加更多动物。在运行时,当用信息填写适当的框并按下添加动物按钮时,信息应该添加到列表视图中的一行(任务的重要部分。当我可以将它显示在列表框)。

当我将信息打印到列表框时,我只是通过 public string AnimalInformation() 从 Animal class 向 AnimalManager 发送了一个包含适当信息的字符串,AnimalManager 编译了一个数组并将其发送到 Form1被打印。因为我想在列表视图中显示它,我想我应该将 AnimalInformation() 变成一个数组,这样我在通过 AnimalManager 后得到一个二维数组,就像打印时显示的一样。但是,当 运行 程序并尝试添加动物时,我在我的 AnimalManager 中收到异常消息 System.NullReferenceException: 'Object reference not set to an instance of an object.'

这是Animal中的方法class:

        public string[] AnimalInformation()
        {
            string[] strOut = { id, name, age.ToString(), gender.ToString(), FriendlyStr()};
            return strOut;
        }

这是AnimalManager中的方法class:

        public string[][] GetAnimalInfoArray()
        {
            string[][] animals = new string[animalList.Count][];
        

            for(int i = 0; i < animalList.Count; i++)
            {
                Animal animal = animalList[i];

                for(int j = 0; j < animal.CountAnimalInfo(); j++)
                {
                    string[] info = animal.AnimalInformation();
                    animals[i][j] = info[j];
                }//here comes the exception

            }
            return animals;
        }

并且由于我不太熟悉 listview(阅读:一点也不熟悉),这是我编写的循环,用于在我的 UpdateGUI() 方法中将其全部打印到 listview 中,以防这是导致的原因麻烦:

            if (manager.Count() > 0)
            {
                foreach(string[] row in manager.GetAnimalInfoArray())
                {
                    foreach(string item in row)
                        lvwAnimals.Items.Add(item);
                }
            }

我已经在这里待了几个小时了,不知道发生了什么。我走在正确的轨道上吗?我必须完全返工吗?在大括号后收到错误消息我做错了什么?

我知道这不会直接回答,JeremyLakeMan 评论您现在遇到问题的原因。但这是我会做的

给定一个名为 animalList 的 Animals IEnumerable(您已经拥有)

假设动物看起来像这样

public class Animal{
      public string ID;
      public String Name; 
      public int Age;
}

现在

        foreach(var animal in animals)
        {
                lvwAnimals.Items.Add(animal.ID);
                lvwAnimals.Items.Add(animal.Name);
                lvwAnimals.Items.Add(animal.Age.ToString());

        }

就是这样,不需要整个 GetAnimalInfoArray

第一个问题是您正在创建一个数组数组,但没有在数组中分配数组...这有点令人困惑,但这是一行:

string[][] animals = new string[animalList.Count][];

animalsstring[]的数组。此时,animals数组中的每个元素都是null,不是数组。您遇到问题的地方是:

animals[i][j] = info[j];

此时animals[i]未初始化(null),所以没有数组供你用j索引。

这个问题有多种解决方法,但最直接的方法是简单地将调用AnimalInformation的结果赋值给数组槽并完成:

public string[][] GetAnimalInfoArray()
{
    string[][] animals = new string[animalList.Count][];
    for(int i = 0; i < animalList.Count; i++)
        animals[i] = animalList[i].AnimalInformation();
    return animals;
}

如果您可以使用 LINQ,那么还有一个更简单的选项:ToArray()

public string[][] GetAnimalInfoArray()
    => animalList.Select(a => a.AnimalInformation()).ToArray();

关于其余代码的一些注释...

您的内循环为信息数组中的每个项目调用 CountAnimalInfo()AnimalInformation()。那是你调用这两种方法的 5 次,每次你至少创建一个数组(我假设你不是从 CountAnimalInfo() 内部调用 AnimalInformation(),如果你是那么那是两个每个项目的数组)。如果您必须循环,最好只调用一次并使用结果数组进行循环。

for (int i = 0; i < animalList.Count; i++)
{
    var info = animalList[i].AnimalInformation();
    animals[i] = new string[info.Length];
    for (int j = 0; j < info.Length; j++)
        animals[i][j] = info[j];
}

您正在将看似显示代码的内容分散到多个方法和 classes 中。虽然有时能够覆盖 sub-classes 中的内容很有用,但通常(至少以我的经验)将显示代码放在一个地方是更可取的:单个方法或紧密耦合的方法组单身 class。 Animal 不需要知道它是如何显示的,它只需要呈现其他代码可以使用的属性。您的 AnimalManager class 可能也不需要充当您的显示代码的 go-between,这取决于显示代码来确定应该如何显示。试试这个:

foreach (var animal in manager.animalList)
{
    lvwAnimals.Items.Add(animal.id);
    lvwAnimals.Items.Add(animal.name);
    lvwAnimals.Items.Add(animal.age.ToString());
    lvwAnimals.Items.Add(animal.gender.ToString());
    lvwAnimals.Items.Add(animal.FriendlyStr());
}

这样您就将 'display' 问题与 non-display class 问题分开了,让他们更专注于自己的工作。还有额外的好处,以后调试的代码行少了很多。