Custom Collection返回第一个元素为空

时间:2011-07-04 14:41:19

标签: c# generics collections

我正在尝试重新创建通用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的工作方式完全相同,但我只是想了解它背后的逻辑。谢谢你的帮助。

7 个答案:

答案 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?>();