自定义集合返回第一个元素为空

本文关键字:元素 第一个 集合 返回 自定义 | 更新日期: 2023-09-27 18:01:22

我正在尝试重新创建通用列表集合。这是我的代码添加项目的集合,并显示所有他们:

public class Collect<TItem>
{
    public Collect<TItem> collectObject;
    public TItem firstObject;
    public void Add(TItem item)
    {
        if (collectObject == null)
        {
            collectObject = new Collect<TItem>();
            collectObject.firstObject = item;
        }
        else 
        {
            this.collectObject.Add(item);
        }
    }
    public void Show()
    {
        if (firstObject != null)
            Console.WriteLine(firstObject.ToString());
        if (collectObject != null)
            collectObject.Show();           
    }

你可以这样使用这个类:

Collect<int> test = new Collect<int>();
        test.Add(2);
        test.Add(10);
        test.Add(30);
        test.Add(3);
        test.Show();

打印上述所有值,但第一项始终为0。

0
2
10
30
3

这是因为第一个firstObject变量从未被分配并获得默认值,但我无法想出一种方法来解决这个问题。我在书中了解到这在构造函数中分配了第一个firstObject变量,该构造函数期望TItem对象,但我想在不使用此集合的构造函数(以重新创建列表)的情况下这样做

我知道这与泛型列表的工作原理完全相同,但我只是想了解它背后的逻辑。谢谢你的帮助。

自定义集合返回第一个元素为空

您可以使您的TItem为空,这允许您的测试工作。此外,您需要在Collect的顶部实例中设置firstObject,而不是引用的实例。

public class Collect<TItem> where TItem : struct
{
    public Collect<TItem> collectObject;
    public TItem? firstObject;
    public void Add(TItem item)
{
        if (collectObject == null)
        {
            collectObject = new Collect<TItem>();
            firstObject = item;
        }
        else 
        {
            this.collectObject.Add(item);
        }
    }
    public void Show()
    {
        if (firstObject.HasValue)
            Console.WriteLine(firstObject.ToString());
        if (collectObject != null)
            collectObject.Show();           
    }
}

好的,这让我很头疼,但我认为你应该这样做:

if (collectObject == null)
    {
        collectObject = new Collect<TItem>();
        this.firstObject = item;
    }

因为否则你永远不会给你创建的对象的firstobject属性赋值

你做错的是collectObject.firstObject = item;应该是this.firstObject = item;

我认为你只需要改变这一行:collectObject。firstObject = item;来firstObject = item;

这样,您的自定义集合将始终由"头"answers"尾"表示-我想这就是您想要实现的。

换句话说,当添加一个项目时,你说"如果这是第一次添加,那么这是我的列表的'头',否则-将它插入列表的'尾'"。打印是用同样的想法-打印"头",然后调用尾部的打印方法(在你的代码'Show'方法)。

首先,这肯定不是System.Collections.Generic.List<T>的工作方式。它在内部使用数组,而不是像您那样使用单链表。LinkedList<T>有点类似于您的集合,除了它使用双重喜欢列表。

现在,回到你的问题上来。您的集合的问题是,它不能表示一个空值,似乎你想要的。我的建议是创建另一个代表整个集合的公共类,并将Collect<T>仅更改为内部实现(我们称之为Node<T>)。这样,新的集合类在第一次构造时可以包含nullNode<T>的引用,这表示一个空集合。

如果这是生产代码,我很确定您实际上需要这样做,因为您将希望在每个集合的基础上保留一些信息(如计数)。

另一种选择(函数式语言中的列表通常采用)是创建类似于下面的继承层次结构:
abstract class Node<T>
{ }
class FullNode<T> : Node<T>
{
    public T Item { get; private set; }
    public Node<T> Next { get; private set }
    // constructor and possibly other members
}
class EmptyNode<T> : Node<T>
{ }

这样,您就可以使用不同的类型来表示完整节点和空节点。在这些列表中,通常将新项添加到前面,而不是后面。

我至少还会建议另外一个改进,关于添加的速度,但我想你的书会涉及到这一点。

同样,我很确定就是这样,但我真的希望您不打算在任何类型的生产环境中使用此代码,并且它只是一个学习练习。

只是为了添加更多的信息…

将0写出来的原因是因为您对firstObject进行了!= null检查。显然,整数的默认值不是空,而是零,所以当firstObject没有被设置时,它将是零而不是空。我想如果你想排除非默认类型的任何值你可以将检查更改为:

if (firstObject != default(TItem))

这可能不是你想要的,因为我确信0在这个例子中可能是一个有效值

尝试一个可空的类型

Collect<int?> test = new Collect<int?>();