我正在尝试重新创建通用List集合。这是我将代码添加到集合并显示所有内容的代码:
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
对象,但我想在不使用此集合的构造函数的情况下(重新创建一个List)
我知道这与通用List的工作方式完全相同,但我只是想了解它背后的逻辑。谢谢你的帮助。
答案 0 :(得分:1)
您可以使您的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();
}
}
答案 1 :(得分:0)
你做错了,collectObject.firstObject = item;
应该是this.firstObject = item;
答案 2 :(得分:0)
好的,这是我的头脑,但我想你想做的事情是:
if (collectObject == null)
{
collectObject = new Collect<TItem>();
this.firstObject = item;
}
因为否则你实际上永远不会将任何对象分配给你正在创建的对象的firstobject属性。
答案 3 :(得分:0)
我认为你只需改变这条线: collectObject.firstObject = item; 至 firstObject = item;
这样,您的自定义集合将始终由“头部”和“尾部”表示 - 我认为这是您试图完成的内容。
换句话说,当添加一个项目时,你说“如果这是第一次添加,那么这是我列表的'头',否则 - 将它插入列表的'尾部'”。打印具有相同的想法 - 打印“head”然后调用tail的打印方法(在代码'Show'方法中)。
答案 4 :(得分:0)
首先,这肯定不是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>
{ }
这样,您可以使用单独的类型来表示完整节点和空节点。在这些列表中,通常会在前面添加新项目,而不是在后面添加。
关于添加速度,我建议至少另外一项改进,但我想你的书会达到这一点。
另外,我很确定是这种情况,但我真的希望你不打算在任何一种生产环境中使用这个代码,而这只是一个学习练习。
答案 5 :(得分:0)
只是添加更多信息......
写出0的原因是因为你对firstObject进行了!= null检查。显然,整数的默认值不为null,它为零,因此当尚未设置firstObject时,它将为零而不为null。我想如果您想要排除任何非该类型默认值,您可以将支票更改为:
if (firstObject != default(TItem))
这可能不是你想要的,但我确信在这个例子中零可能是一个有效值。
答案 6 :(得分:0)
尝试可以为空的
Collect<int?> test = new Collect<int?>();