2011-07-04 57 views
1

我试图重新创建通用列表集合。这是我的代码项添加到收集和显示所有的人:自定义集合返回第一个元素为空

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变量从未被分配并得到默认值,但我不能想出一个办法来修复此问题。这本书我学到这个分配在期望一个TItem对象的构造第一firstObject变量,但我想这样做,而无需使用一个构造这个集合(重新建立一个列表)

我知道这是完全一样的像通用列表如何工作,但我只想了解它背后的逻辑。谢谢您的帮助。

回答

0

什么你做错了,是collectObject.firstObject = item;应该是this.firstObject = item;

+2

否则,很快就会让你一个'StackOverflowException'与OP的一流的设计,当你试图创建'收集'对象的无限窝。 – LukeH

+0

您是对的,编辑我的回答 – hungryMind

+0

您的编辑只是将幻像值转移到输出序列的末尾,而不是开头:'{2,10,30,3,0}'而不是'{0,2,10 ,30,3}'。 – LukeH

0

OK,这是做我的头,但我想你想要做的事,如:

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

,否则你永远不会真正分配对您正在创建的对象的第一个对象属性进行任何赋值。

+0

这不正是OP已经有的代码吗? – LukeH

+0

this.firstobject,而不是collectObject.firstObject。一个关键的区别。 –

+0

这几乎是我的想法,但我读得越多,代码就越少,因为发布的内容我看不出它是如何打印除2之外的任何内容的。编辑 - 看起来我错了,只打印2 ...你的改变是正确的。 – DoctorMick

0

我认为你只需要改变一行: collectObject.firstObject = item; 至 firstObject = item;

这样您的自定义集合将始终由“头”和“尾巴”表示 - 我认为这就是您正在尝试实现的目标。

换句话说,当添加一个项目时,你会说:“如果这是第一次添加,那么这是我的'头'列表,否则 - 将它插入到列表的”尾部“。打印有相同的想法 - 打印“头”,然后调用尾巴的打印方法(在代码中的“显示”方法)。

0

首先,这当然不是System.Collections.Generic.List<T>的工作方式。它在内部使用数组,而不是像你一样单独链接列表。 LinkedList<T>有点类似于你的收藏,除了它使用双喜列表。

现在,到你的问题。您收藏的问题在于它无法表现出一个空值,而且您似乎想要这样做。我建议的是创建另一个公开课,代表整个集合,并将您的Collect<T>仅更改为内部实现(我们称之为Node<T>)。这样,新建集合类可以包含null参考Node<T>,当它第一次构建时,它表示一个空集合。

如果这是生产代码,我敢肯定你实际上需要做这样的事情,因为你要保留一些信息在每个集合的基础上(如count)。

另一种选择(通常在功能性语言采取列表)是创建一个类似于以下内容的继承层次:

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

我想补充一点点信息...

0被写出来的原因是因为你对firstObject一个!= NULL检查。显然,整数的默认值不为空,它是零,所以当第一个对象没有被设置时,它将是零并且不为空。我想,如果要排除是不是该类型的默认,你可以改变你的支票为任意值:

if (firstObject != default(TItem)) 

这可能不是你想要什么,虽然我敢肯定,零可能是一个有效值在这种情况下。

0

尝试空类型

Collect<int?> test = new Collect<int?>(); 
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();   
    } 
} 
相关问题