自定义集合返回第一个元素为空
本文关键字:元素 第一个 集合 返回 自定义 | 更新日期: 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>
)。这样,新的集合类在第一次构造时可以包含null
对Node<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?>();