The task of implementing a doubly linked list in c#

To the essence of the question: I implemented a doubly linked list, do not ask why, I know that there is such a list already in the generics. And everything seems to work) BUT, I send it to the test, where does the NullReferenceException error appear in the testing system? Where that is not exactly specified. The tri-kach blocks covered everything - nothing helped. Look who's interested in what's wrong? The class of the list item, although it is not important:

     //элемент связанного списка
public class ListItem : IListItem
{
    public ListItem prev { get; set; }
    public ListItem next { get; set; }
    private object _val;
    public ListItem(object obj, IListItem prev = null)
    {
        if (obj!=null)
        {
            this._val = obj;
        }

    }

    //предыдущий связанный элемент списка
    public IListItem Prev()
    {
        try
        {
            return prev;
        }
        catch (Exception)
        {

            return new ListItem(999);
        }
    }
    public void invalidate()
    {
        prev = null;
        next = null;
        _val = null;
    }

    //следующий связанный элемент списка
    public IListItem Next()
    {
        try
        {
            return next;
        }
        catch (Exception)
        {

            return new ListItem(999);
        }

    }

    //хранимое значение
    public object Value { get {
            if (_val != null)
            {
                return this._val;
            }
            else return null;

        } }
}

    Сам класс:


     //прямой связанный список
public class LinkedList : ILinkedList
{
    private ListItem head;

    public int count;
    public LinkedList()
    {
        count = 0;
    }

    //добавить элемент в начало
    public void AddFirst(IListItem item)
    {                    
        if (item == null)
        {
            return;
        }
        if (head==null)
        {
            AddToEmtyist(item);
            return;
        }
        ListItem newItem = (ListItem)item;
        newItem.next = head;
        newItem.prev = head.prev;
        head.prev.next = newItem;
        head.prev = newItem;
        head = newItem;
        count++;           
    }

    //добавить элемент в конец
    public void AddLast(IListItem item)
    {   
        if (item == null)
        {
            return;
        }
        if (head == null)
        {
            AddToEmtyist(item);
            return;
        }

        ListItem newItem = (ListItem)item;
        newItem.next = head;
        newItem.prev = head.prev;
        head.prev.next = newItem;
        head.prev = newItem;            
        count++;            
    }

    private void AddToEmtyist(IListItem item)
    {
        try
        {           
        ListItem newItem = (ListItem)item;
        newItem.next = newItem;
        newItem.prev = newItem;
        head = newItem;
        count++;
        }
        catch (Exception err)
        {

            throw;
        }
    }



    //вставить элемент перед элементом с указанным индексом
    //если элемента нет - вставить в конец
    public void Insert(IListItem item, int index)
    {
        try
        {


        if (item==null)
        {
            return;
        }
        int i = 0;
        ListItem replaceItem = head;
        if (index > (count-1))
        {
            AddLast(item);
            return;
        }
        if (index==0)
        {
            AddFirst(item);
        }
        while (index != i)
        {
            replaceItem = replaceItem.next;
            i++;
        }

        ListItem newItem = (ListItem)item;

        newItem.next = replaceItem;
        newItem.prev = replaceItem.prev;

        replaceItem.prev.next = newItem;
        replaceItem.prev = newItem;

        count++;
        }
        catch (Exception err)
        {


        }
    }

    //проверка есть ли эелементы в списке
    public bool IsEmpty()
    {
        if (count > 0)
        {
            return false;
        }
        else return true;
    }

    //вернуть первый эелемент в списке
    public IListItem GetFirstItem()
    {
        if (head != null)
        {
            return head;
        }
        else return null;

    }

    //вернуть все элементы списка, кроме первого
    public IEnumerable<IListItem> GetAll()
    {
        if (count==0)
        {
            return null;
        }
        List<IListItem> rez = new List<IListItem>();
        int cnt = 0;
        ListItem currItem = head;
        while (cnt != (count))
        {
            if (currItem!=head)
            {
               rez.Add(currItem);
            } 
            currItem = currItem.next;
            cnt++;
        }
        return rez;
    }

    //очистить список
    public void Clear()
    {
        ListItem current =(ListItem)head;
        while (current != null)
        {
            ListItem temp = current;
            current = (ListItem)current.Next();
            temp.invalidate();
        }

        head = null;
        count = 0;
    }

    //сортировка списка в обратном порядке
    public void Reverse()
    {
        ListItem node = head;
        do
        {
            ListItem temp = node.next;
            node.next = node.prev;
            node.prev = temp;
            node = node.prev;
            if (temp == head)
            {
                break;
            }
        }
        while (true);

        head = head.next;
    }
}
Author: A K, 2017-09-25

1 answers

It is easy to reproduce the problem

    var l = new LinkedList();   

    foreach (var i in l.GetAll()) // l.GetAll() вернет null
    {
    }

Threw comments on the code

// Что не так:
public class ListItem : IListItem
{
    public ListItem prev { get; set; }
    public ListItem next { get; set; }
    private object _val;

Prev not used

    public ListItem(object obj, IListItem prev = null)
    {
        if (obj != null)
        {
            this._val = obj;
        }

    }

    //предыдущий связанный элемент списка
    public IListItem Prev()
    {
        try
        {

Here, with this code, there will never be an exception

            return prev;
        }
        catch (Exception)
        {

            return new ListItem(999);
        }
    }
    public void invalidate()
    {
        prev = null;
        next = null;
        _val = null;
    }

    //следующий связанный элемент списка
    public IListItem Next()
    {
        try
        {

There can be no exception here, it's just a return of the link

            return next;
        }
        catch (Exception)
        {

            return new ListItem(999);
        }

    }

    //хранимое значение
    public object Value
    {
        get
        {

The entire construction is replaced with return this._val

            if (_val != null)
            {
                return this._val;
            }
            else return null;

        }
    }
}




     //прямой связанный список
public class LinkedList : ILinkedList
{
    private ListItem head;

    public int count;
    public LinkedList()
    {
        count = 0;
    }

    //добавить элемент в начало
    public void AddFirst(IListItem item)
    {
        if (item == null)
        {
            return;
        }
        if (head == null)
        {
            AddToEmtyist(item);
            return;
        }
        ListItem newItem = (ListItem)item;
        newItem.next = head;

Head.prev is always null by logic

        newItem.prev = head.prev;

If head.prev == null, there will be an exception

        head.prev.next = newItem;
        head.prev = newItem;
        head = newItem;
        count++;
    }

    //добавить элемент в конец
    public void AddLast(IListItem item)
    {
        if (item == null)
        {
            return;
        }
        if (head == null)
        {
            AddToEmtyist(item);
            return;
        }

        ListItem newItem = (ListItem)item;
        newItem.next = head;

Head.prev by logic always null

        newItem.prev = head.prev;

If head.prev == null, there will be an exception

        head.prev.next = newItem;
        head.prev = newItem;
        count++;
    }

    private void AddToEmtyist(IListItem item)
    {
        try
        {
            ListItem newItem = (ListItem)item;

Why do the next one and the previous one point to the same thing, and to themselves?

            newItem.next = newItem;
            newItem.prev = newItem;
            head = newItem;
            count++;
        }
        catch (Exception err)
        {

If there is an exception, it will not stop here - you run it further yourself

            throw;
        }
    }



    //вставить элемент перед элементом с указанным индексом
    //если элемента нет - вставить в конец
    public void Insert(IListItem item, int index)
    {
        try
        {


            if (item == null)
            {
                return;
            }
            int i = 0;
            ListItem replaceItem = head;
            if (index > (count - 1))
            {
                AddLast(item);
                return;
            }
            if (index == 0)
            {
                AddFirst(item);
            }
            while (index != i)
            {
                replaceItem = replaceItem.next;
                i++;
            }

            ListItem newItem = (ListItem)item;

            newItem.next = replaceItem;
            newItem.prev = replaceItem.prev;

            replaceItem.prev.next = newItem;
            replaceItem.prev = newItem;

            count++;
        }
        catch (Exception err)
        {


        }
    }

    //проверка есть ли эелементы в списке
    public bool IsEmpty()
    {
        if (count > 0)
        {
            return false;
        }
        else return true;
    }

    //вернуть первый эелемент в списке
    public IListItem GetFirstItem()
    {
        // просто return head;
        if (head != null)
        {
            return head;
        }
        else return null;

    }

    //вернуть все элементы списка, кроме первого
    public IEnumerable<IListItem> GetAll()
    {
        if (count == 0)
        {

If you return null as a result , you get nullreferenceexceprion in the calling code. Return Enumerable.Empty<IListItem>();

            return null;
        }
        List<IListItem> rez = new List<IListItem>();
        int cnt = 0;
        ListItem currItem = head;

Why are there counters at all? Just go through the list until you run out.

        while (cnt != (count))
        {
            if (currItem != head)
            {
                rez.Add(currItem);
            }
            currItem = currItem.next;
            cnt++;
        }
        return rez;
    }

    //очистить список
    public void Clear()
    {
        ListItem current = (ListItem)head;
        while (current != null)
        {
            ListItem temp = current;
            current = (ListItem)current.Next();
            temp.invalidate();
        }

        head = null;
        count = 0;
    }

    //сортировка списка в обратном порядке
    public void Reverse()
    {
        ListItem node = head;
        do
        {
            ListItem temp = node.next;
            node.next = node.prev;
            node.prev = temp;
            node = node.prev;
            if (temp == head)
            {
                break;
            }
        }
        while (true);

        head = head.next;
    }
}
 2
Author: tym32167, 2017-09-25 22:52:56