C# 运行时错误 : InvalidCastException with Generic Class Instance

标签 c# generics casting runtime-error typechecking

我是一名 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 是每个类实例的基础、根类。因此,我已将堆栈实例作为对象传递给方法,假设这不会成为问题,因为 int,Int32 的别名也从 Object 扩展而来。

在下方,我添加了用于编译上述测试代码的全部剩余文件;

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();
        }
    }
}

最佳答案

从根本上说,您不应该尝试制作 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);

...没问题。

关于C# 运行时错误 : InvalidCastException with Generic Class Instance,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34015095/

相关文章:

c# - 为什么我无法访问 System.EventArgs 的 KeyCode 成员?

c# - 如何在网络上的所有机器上安装 .NET Windows Forms 应用程序?

javascript - 有没有办法在泛型 (<T>) 函数/类 (Typescript) 中获取泛型类型的名称?

java - Java : a design problem 中具有泛型类型的抽象工厂

c++ - 如何将 LONG 转换为 CString?

c# - 输出文本的第一个字母随着后续迭代而消失

C# 比较评级值

java - 在 Kotlin 中扩展泛型类

Java 继承 - 使用相同方法的两个类

c++ - 从较大的数据类型(结构)转换为较小的数据类型