【问题标题】:Generic Linked List通用链表
【发布时间】:2010-06-30 14:48:41
【问题描述】:

在发布我的问题之前,我想告诉您,我之前没有 .Net 技术方面的经验,并且最近开始学习 C#(和 WPF)。我的公司正在寻求转向 .Net 技术,而我是团队中唯一一个学习它的人,所以除了你们之外,没有人可以讨论或提问。因此,如果我的问题过于愚蠢或过于基本,请多多包涵。

我试图创建一个通用的链表类来允许创建不同类型的链表。我编写了以下代码,并希望您就我是否正确编写了此代码提出建议。欢迎以任何方式改进代码的任何建议。

主程序

class Program
{
    static void Main(string[] args)
    {
        GenLinkedList<string> list = new GenLinkedList<string>("abc");
        list.AddtoList("def");
        int i = 0;
        string[] arr = new string[10];
        list.LinkedList.CopyTo(arr,0);
        for (i = 0; i < list.LinkedList.Count; i++)
        {
            Console.WriteLine(arr[i]);
        }

        GenLinkedList<int> listInt = new GenLinkedList<int>(1);
        listInt.AddtoList(2);
        i = 0;
        int[] arrInt = new int[10];
        listInt.LinkedList.CopyTo(arrInt, 0);
        for (i = 0; i < listInt.LinkedList.Count; i++)
        {
            Console.WriteLine(arrInt[i]);
        }

    }
}

类 GenLinkedList

public class GenLinkedList<T>
{
    private LinkedList<T> _linkedlist;
    public GenLinkedList(T a)
    {
        _linkedlist = new LinkedList<T>();
        _linkedlist.AddLast(a);
    }

    public LinkedList<T> LinkedList
    {
        get
        {
            return _linkedlist;
        }
    }

    public void AddtoList(T a)
    {
        LinkedList.AddLast(a);
    }
}

【问题讨论】:

标签: c# generics


【解决方案1】:

为什么不使用System.Collections.Generic.LinkedList&lt;T&gt;?您已经在 GenLinkedList&lt;T&gt; 内部使用它,而且它已经为您通用。

这是框架提供的通用双向链表实现。阅读它:

MSDN - LinkedList(T) Class

如果您将创建通用链接列表作为练习,则不应基于现有通用链接列表的实现。通过包装已经完全可以完成您需要做的事情,您真的不会学到任何东西。

【讨论】:

  • 我知道。实际上,我正在从一本书中进行练习测试,练习是“创建一个链表泛型类,使您能够创建一系列不同类型的对象”。我想它只是想让我检查我是否可以编写一个泛型类??
  • 他知道——他的实现使用了它。
  • @user366436:如果你试图完成一个练习来创建一个链表,那么使用一个预建的链表就是作弊。如果您纯粹将其作为练习,那么使用预构建的链表类是浪费时间。
  • 练习题,比如不想你在内部使用LinkedList&lt;T&gt;;他们希望你自己写。
  • @user366436 - 如果您只是想实现一个通用类,那么可以。这就是你要做的。这并没有真正让您接触到更复杂的泛型细节,因为您在内部使用现有的泛型类。
【解决方案2】:

1

.NET 框架中已经存在通用链表实现:LinkedList&lt;T&gt;。但是你已经知道了;你的代码包装了它。

2

好的,你知道的。那你为什么要把它包起来?您似乎已经实现的唯一功能是AddtoList,它没有做任何LinkedList&lt;T&gt; 本身还没有做的事情(毕竟,这只是LinkedList&lt;T&gt;.AddLast 的一个薄包装)。这意味着您的GenLinkedList&lt;T&gt; 类确实提供链表的功能;它基本上是一个只添加的集合(它可以很容易地用List&lt;T&gt;Stack&lt;T&gt;Queue&lt;T&gt; 实现——任何东西,真的)。

3

假设您确实有充分的理由包装LinkedList&lt;T&gt;(例如,您计划添加更多实际利用LinkedList&lt;T&gt;行为的功能和/或——这是一个关键因素——你想限制调用代码能够与列表交互的方式(例如,不删除)),你真的根本不应该暴露您的LinkedList&lt;T&gt; 成员。包装器的目的就是:包装。你拿一个现有的类,基本上给它一种新的接口。通过直接暴露底层对象,你会削弱你的包装器。可以绕过包装器中的任何其他限制/验证/逻辑。

因此,例如,如果您希望能够将列表复制到数组中,而不是这样做:

list.LinkedList.CopyTo(arr,0);

您将在您的GenLinkedList&lt;T&gt; 类中实现一个CopyTo 方法(可以简单地调用_linkedlist.CopyTo)并使用它。

但我真的认为您应该问自己的第一个问题是您首先要通过包装 LinkedList&lt;T&gt; 来完成什么。

【讨论】:

  • 实际上,我正在做一个 MCTS 书中的练习测试,练习是“创建一个链表泛型类,使您能够创建一系列不同类型的对象。”现在我认为他们希望我实现自己的链表。我会尝试这种方法。另外,我会尝试在我的代码中实现您的第三个建议。谢谢。我猜你的意思是用户应该只能访问我希望他们访问的那些方法。对吗?
  • @user366436:没错。不过,现在我想指出其他一点。如果练习是编写一个可以“创建不同类型的对象链”的列表,那么编写一个generic类确实不是开始的正确方法,因为它将您限制为特定类型。但由于该练习还包括“通用”一词,我不太确定这本书要你做什么。
【解决方案3】:

显而易见的问题是为什么您不直接使用LinkedList&lt;T&gt;,尽管看起来您正在尝试模拟单链表。

在这种情况下,您应该避免暴露底层的LinkedList&lt;T&gt; 实例,因为任何客户端都可以直接操作它。我还将实现IEnumerable&lt;T&gt;,这将使您的列表可供 linq 使用。

【讨论】:

  • IEnumerable 绝对是你的朋友。
【解决方案4】:

我从http://msdn.microsoft.com/en-us/library/0x6a29h6.aspx得到这个
适合我。

namespace GenLinkedList
{
    class Program
    {
        static void Main(string[] args)
        {
            GenericList<object> list = new GenericList<object>();

            // Add items to list.
            list.AddHead("some string here");
            list.AddHead(DateTime.Today.ToLongDateString());
            list.AddHead(13);
            list.AddHead(13.005);
            for (int x = 0; x < 10; x++)
            {
                list.AddHead(x);
            }

            // Enumerate list.
            foreach (object i in list)
            {
                Console.WriteLine(i + " " + i.GetType());
            }
            Console.WriteLine("\nDone");
        }
    }
}

namespace GenLinkedList
{
    // type parameter T in angle brackets
    class GenericList<T>
    {
        // The nested class is also generic on T.
        public class Node
        {
            private Node next;

            // T as private member data type.
            private T data;


            // T used in non-generic constructor.
            public Node(T t)
            {
                next = null;
                data = t;
            }

            public Node Next
            {
                get { return next; }
                set { next = value; }
            }

            public T Data
            {
                get { return data; }
                set { data = value; }
            }
        }

        private Node head;

        // constructor
        public GenericList()
        {
            head = null;
        }

        // T as method parameter type
        public void AddHead(T t)
        {
            Node n = new Node(t);
            n.Next = head;
            head = n;
        }

        public IEnumerator<T> GetEnumerator()
        {
            Node current = head;

            while (current != null)
            {
                yield return current.Data;
                current = current.Next;
            }

        }
    }
}

【讨论】:

  • 问题是审查代码并提供 cmets,而不是提供更多代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-04
  • 2016-10-01
  • 1970-01-01
相关资源
最近更新 更多