C#运行时错误:具有泛型类实例的InvalidCastException

本文关键字:实例 InvalidCastException 泛型类 运行时错误 | 更新日期: 2023-09-27 18:25:06

我是一名java开发人员,刚接触C#,我在下面的代码中遇到了InvalidCastException

我已经实现了一个基于自定义双链表实现的队列。这两种实现都是通用的,因此,在测试代码中,我希望使用通用的打印方法。

下面的测试代码运行良好;

using System;
using System.Collections.Generic;
namespace Queue01
{
    public class TestQueue
    {
        public static void Main(string[] args)
        {
            Queue<int> queue = new Queue<int>();
            queue.Enqueue(4);
            queue.Enqueue(5);
            queue.Enqueue(6);
            Console.WriteLine("*****");
            PrintQueue(queue);
            Console.WriteLine("*****");
            int first = queue.Dequeue();
            Console.WriteLine("Enqueued value : " + first);
            Console.WriteLine("*****");
            PrintQueue(queue);
        }
        public static void PrintQueue(object queue)
        {
            Queue<int> q = (Queue<int>)queue;
            foreach (object i in q)
            {
                Console.WriteLine(i);
            }
        }
    }
}

然而,我想让PrintQueue静态方法适用于所有类型,因此我更改了方法代码如下;

public static void PrintQueue(object queue)
{
    Queue<object> q = (Queue<object>)queue;
    foreach (object i in q)
    {
        Console.WriteLine(i);
    }
}

整个测试代码不起作用,如下所示;

using System;
using System.Collections.Generic;
namespace Queue01
{
    public class TestQueue
    {
        public static void Main(string[] args)
        {
            Queue<int> queue = new Queue<int>();
            queue.Enqueue(4);
            queue.Enqueue(5);
            queue.Enqueue(6);
            Console.WriteLine("*****");
            PrintQueue(queue);
            Console.WriteLine("*****");
            int first = queue.Dequeue();
            Console.WriteLine("Enqueued value : " + first);
            Console.WriteLine("*****");
            PrintQueue(queue);
        }
        public static void PrintQueue(object queue)
        {
            Queue<object> q = (Queue<object>)queue;
            foreach (object i in q)
            {
                Console.WriteLine(i);
            }
        }
    }
}

然后我就陷入了InvalidCastException。问题在哪里?如何修复此异常?使此代码通用的最佳做法是什么?

在java中,Object是每个类实例的基础根类。因此,我已经将堆栈实例作为对象传递给该方法,假设它不会成为问题,因为Int32的别名int也是从object扩展而来的。

下面,我将添加用于编译上面的测试代码的全部rest文件;

1) 这是我在双链表实现中使用的DoublyLinkedListNode类;

using System;
using System.Collections.Generic;
namespace Queue01
{
    public class DoublyLinkedListNode<T>
    {
        // Fields
        public T Value { get; set; }
        public DoublyLinkedListNode<T> Previous { get; set; }
        public DoublyLinkedListNode<T> Next { get; set; }
        public DoublyLinkedListNode(T value)
        {
            Value = value;
        }
    }
}

2) 这是我的DoublyLinkedList类,它为我将要使用的队列实现实现了一个双链表;

using System;
using System.Collections.Generic;
namespace Queue01
{
    public class DoublyLinkedList<T> : ICollection<T>
    {
        #region Fields
        public DoublyLinkedListNode<T> Head { get; private set; }
        public DoublyLinkedListNode<T> Tail { get; private set; }
        #endregion
        #region Constructor
        #endregion
        #region Add
        public void AddFirst(T value)
        {
            AddFirst(new DoublyLinkedListNode<T>(value));
        }
        public void AddFirst(DoublyLinkedListNode<T> node)
        {
            DoublyLinkedListNode<T> temp = Head;
            Head = node;
            Head.Next = temp;
            //if(Count == 0)
            if (Empty)
            {
                Tail = Head;
            }
            else
            {
                temp.Previous = Head;
            }
            Count++;
        }
        public void AddLast(T value)
        {
            AddLast(new DoublyLinkedListNode<T>(value));
        }
        public void AddLast(DoublyLinkedListNode<T> node)
        {
            //if (Count == 0)
            if (Empty)
            {
                Head = node;
            }
            else
            {
                Tail.Next = node;
                node.Previous = Tail;
            }
            Tail = node;
            Count++;
        }
        #endregion
        #region Remove
        public void RemoveFirst()
        {
            //if (Count != 0)
            if (!Empty)
            {
                Head = Head.Next;
                Count--;
                if (Count == 0)
                {
                    Tail = null;
                }
                else
                {
                    Head.Previous = null;
                }
            }
        }
        public void RemoveLast()
        {
            //if (Count != 0)
            if (!Empty)
            {
                if (Count == 1)
                {
                    Head = null;
                    Tail = null;
                }
                else
                {
                    Tail.Previous.Next = null;
                    Tail = Tail.Previous;
                }
                Count--;
            }
        }
        #endregion
        #region ICollection
        public int Count
        {
            get;
            private set;
        }
        public void Add(T item)
        {
            AddFirst(item);
        }
        public bool Contains(T item)
        {
            DoublyLinkedListNode<T> current = Head;
            while (current != null)
            {
                if (current.Value.Equals(item))
                {
                    return true;
                }
                current = current.Next;
            }
            return false;
        }
        public void CopyTo(T[] array, int arrayIndex)
        {
            DoublyLinkedListNode<T> current = Head;
            while (current != null)
            {
                array[arrayIndex++] = current.Value;
                current = current.Next;
            }
        }
        public bool IsReadOnly
        {
            get
            {
                return false;
            }
        }
        public bool Remove(T item)
        {
            DoublyLinkedListNode<T> previous = null;
            DoublyLinkedListNode<T> current = Head;
            while (current != null)
            {
                if (current.Value.Equals(item))
                {
                    if (previous != null)
                    {
                        previous.Next = current.Next;
                        if (current.Next == null)
                        {
                            Tail = previous;
                        }
                        else
                        {
                            current.Next.Previous = previous;
                        }
                        Count--;
                    }
                    else
                    {
                        RemoveFirst();
                    }
                    return true;
                }
                previous = current;
                current = current.Next;
            }
            return false;
        }
        public void Clear()
        {
            Head = null;
            Tail = null;
            Count = 0;
        }
        //System.Collections.Generic.IEnumerator<T> System.Collections.Generic.IEnumerable<T>.GetEnumerator()
        public IEnumerator<T> GetEnumerator()
        {
            DoublyLinkedListNode<T> current = Head;
            while (current != null)
            {
                yield return current.Value;
                current = current.Next;
            }
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            //return ((System.Collections.Generic.IEnumerable<T>)this).GetEnumerator();
            return this.GetEnumerator();
        }
        #endregion
        #region helper
        public void PrintEnumerable()
        {
            IEnumerator<T> e = this.GetEnumerator();
            while (e.MoveNext())
            {
                T val = e.Current;
                Console.WriteLine("Value: " + val);
            }
        }
        public void PrintReverse()
        {
            for (DoublyLinkedListNode<T> node = Tail; node != null; node = node.Previous)
            {
                Console.WriteLine(node.Value);
            }
        }
        public bool isEmpty()
        {
            if (Count == 0)
            {
                return true;
            }
            return false;
        }
        public bool Empty { get { return isEmpty(); } }
        public DoublyLinkedListNode<T> First { get { return this.Head; } }
        public DoublyLinkedListNode<T> Last { get { return this.Tail; } }
        #endregion
    }
}

3) 这是我的队列实现,基于我上面使用过的双链表实现;

using System;
using System.Collections.Generic;
namespace Queue01
{
    public class Queue<T> : System.Collections.Generic.IEnumerable<T>
    {
        DoublyLinkedList<T> _items = new DoublyLinkedList<T>();
        LinkedList<T> hede = new LinkedList<T>();
        public void Enqueue(T item)
        {
            _items.AddLast(item);
        }
        public T Dequeue()
        {
            if(_items.Count == 0)
            {
                throw new InvalidOperationException("The queue is empty.");
            }
            T value = _items.First.Value;
            _items.RemoveFirst();
            return value;
        }
        public IEnumerator<T> GetEnumerator()
        {
            return this._items.GetEnumerator();
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }
}

C#运行时错误:具有泛型类实例的InvalidCastException

从根本上讲,您不应该尝试使PrintQueue适用于每个对象,您应该尝试使它适用于任何Queue<T>。。。最简单的方法是将其通用化:

public static void PrintQueue<T>(Queue<T> queue)
{
    foreach (T item in queue)
    {
        Console.WriteLine(item);
    }
}

或者你可以更一般地接受IEnumerable<T>:

public static void PrintSequence<T>(IEnumerable<T> queue)
{
    foreach (T item in queue)
    {
        Console.WriteLine(item);
    }
}

您的原始代码失败了,因为Queue<int>不是Queue<object>。。。事实上,因为Queue<T>T中不是协变的,所以不能将Queue<string>转换为Queue<object>。。。但IEnumerable<T>协变量,因此:

Queue<string> stringQueue = new Queue<string>();
...
PrintSequence<object>(stringQueue);

会没事的。

更改PrintQueue方法怎么样。就像这样:

    public static void PrintQueue<T>(object queue)
    {
        var q = (Queue<T>)queue;
        foreach (var i in q)
            Console.WriteLine(i);
    }

并像这样使用:

PrintQueue<int>(queue);

这样更改代码:

public static void PrintQueue(dynamic queue)
{
    foreach (var i in queue)
    {
        Console.WriteLine(i);
    }
}