C# Runtime Error: InvalidCastException with Generic Class Instance
C# Runtime Error: InvalidCastException with Generic Class Instance
我是一名 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 上,对象是基础,每个 class 实例的根 class。因此,我已将堆栈实例作为对象传递给方法,假设这不会成为问题,因为 int,Int32 的别名也从 Object 扩展而来。
在下面,我添加了我用于编译上面测试代码的全部剩余文件;
1) 这是我在双向链表实现中使用的 DoublyLinkedListNode class;
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 class,它为我将要使用的队列实现实现了双向链表;
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 方法怎么样。就像这样:
public static void PrintQueue<T>(object queue)
{
var q = (Queue<T>)queue;
foreach (var i in q)
Console.WriteLine(i);
}
并像这样使用它:
PrintQueue<int>(queue);
从根本上说,您不应该尝试让 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);
...会没问题。
像这样更改您的代码:
public static void PrintQueue(dynamic queue)
{
foreach (var i in queue)
{
Console.WriteLine(i);
}
}
我是一名 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 上,对象是基础,每个 class 实例的根 class。因此,我已将堆栈实例作为对象传递给方法,假设这不会成为问题,因为 int,Int32 的别名也从 Object 扩展而来。
在下面,我添加了我用于编译上面测试代码的全部剩余文件;
1) 这是我在双向链表实现中使用的 DoublyLinkedListNode class;
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 class,它为我将要使用的队列实现实现了双向链表;
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 方法怎么样。就像这样:
public static void PrintQueue<T>(object queue)
{
var q = (Queue<T>)queue;
foreach (var i in q)
Console.WriteLine(i);
}
并像这样使用它:
PrintQueue<int>(queue);
从根本上说,您不应该尝试让 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);
...会没问题。
像这样更改您的代码:
public static void PrintQueue(dynamic queue)
{
foreach (var i in queue)
{
Console.WriteLine(i);
}
}