C# Runtime Error: InvalidCastException with Generic Class Instance - c#

I'm a java developer and new to C#, I'm stuck with InvalidCastException on the following code below.
I have implemented a Queue, based on a custom Doubly Linked List implementation. Both implementations are generic, and thus, on the test code, I want to use a generic print method.
The test code below is just working fine;
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);
}
}
}
}
However, I want to make the PrintQueue static method working for all types, thus I've changed the method code as below;
public static void PrintQueue(object queue)
{
Queue<object> q = (Queue<object>)queue;
foreach (object i in q)
{
Console.WriteLine(i);
}
}
The whole test code which is not working is as below;
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);
}
}
}
}
And then I'm stuck with the InvalidCastException. Where is the problem and how can I fix this exception and what is the best practice to make this code generic?
On java, Object is the base, root class of every class instance. Thus, I've passed the stack instance as an object to the method, assuming that it won't be a problem because int, the alias for Int32 also extended from the Object.
Here down below, I am adding the whole rest files that I've used for compiling the test code above;
1) Here is the DoublyLinkedListNode class that I used in Doubly Linked List implemetation;
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) Here is my DoublyLinkedList class which implements a doubly linked list for the queue implementation I am going to use;
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) And this is my Queue implementation based on doubly linked list implemetation that I've used above;
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();
}
}
}

Fundamentally, you shouldn't try to make PrintQueue work for every object - you should try to make it work for any Queue<T>... and the simplest way of doing that is to make it generic:
public static void PrintQueue<T>(Queue<T> queue)
{
foreach (T item in queue)
{
Console.WriteLine(item);
}
}
Or you could be more general and accept an IEnumerable<T>:
public static void PrintSequence<T>(IEnumerable<T> queue)
{
foreach (T item in queue)
{
Console.WriteLine(item);
}
}
Your original code is failing because a Queue<int> isn't a Queue<object>... in fact, because Queue<T> isn't covariant in T, you can't convert Queue<string> to Queue<object>... but IEnumerable<T> is covariant, so:
Queue<string> stringQueue = new Queue<string>();
...
PrintSequence<object>(stringQueue);
... would be okay.

What about change PrintQueue method. Just like this:
public static void PrintQueue<T>(object queue)
{
var q = (Queue<T>)queue;
foreach (var i in q)
Console.WriteLine(i);
}
and use it like this:
PrintQueue<int>(queue);

change your code like this:
public static void PrintQueue(dynamic queue)
{
foreach (var i in queue)
{
Console.WriteLine(i);
}
}

Related

why is IsPresentItem giving me error in linklist?

class LinkListGen<T> where T : IComparable
{
private LinkGen<T> list;
public LinkListGen()
{
}
public string DisplayList()
{
Console.WriteLine(test);
foreach (string word in words)
{
Console.Write(word + " ");
}
Console.WriteLine();
Console.WriteLine();
}
public void AddItem(T item)
{
list = new LinkGen<T>(item);
}
public int NumberOfItems()
{
public int Count { get; }
}
public bool IsPresentItem(T item)
{
Link temp = list;
bool result = false;
while (temp != null)
{
if (temp.Data == item)
{
result = true;
break;
}
else
{
temp = temp.Next;
}
}
return result;
}
}
I have been trying to make a generic link list but I am not sure why it is giving me an error. The error is coming from the IsPresentItem. Also I'm not sure when I need to add to the linkListGen. thank you for your time
You've got missing closing brace on the NumberOfItems method because you've declared the Count property within it:
public int NumberOfItems()
{
public int Count { get; }
}
It should be:
public int NumberOfItems()
{
//Do Something
}
public int Count { get; }
The whole class should then look like this:
class LinkListGen<T> where T : IComparable
{
private LinkGen<T> list;
public LinkListGen()
{
}
public string DisplayList()
{
Console.WriteLine(test);
foreach (string word in words)
{
Console.Write(word + " ");
}
Console.WriteLine();
Console.WriteLine();
}
public void AddItem(T item)
{
list = new LinkGen<T>(item);
}
public int NumberOfItems()
{
//Do Something
}
public int Count { get; }
public bool IsPresentItem(T item)
{
Link temp = list;
bool result = false;
while (temp != null)
{
if (temp.Data == item)
{
result = true;
break;
}
else
{
temp = temp.Next;
}
}
return result;
}
}

python&unity3d: Websocket stability

I'm creating an application in Unity3d that communicates with python's websockets library. My python script is as following:
from __future__ import division
import asyncio
import websockets
import time
import os
from threading import Thread
from random import randint
from read import CustOPCLib
import socket
from jsonsocket import Client,Server
class SubHandler(object):
def data_change(self, handle, node, val, attr):
print("Python: New data change event", handle, node, val, attr)
def datachange_notification(self, node, val, data):
print("Data received: ",val)
def event(self, handle, event):
print("Python: New event", handle, event)
p = CustOPCLib()
async def hello(websocket, path):
p.connect() #my own custom library
while True:
datastring = p.opcjson() #this is a jsonstring
await websocket.send(datastring)
#print("> {}".format(datastring))
time.sleep(1)
if __name__ == '__main__':
start_server = websockets.serve(hello, '127.0.0.1', 8765)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
my json string is as following:
{
"Index": 709953575,
"Moto": true,
"Start": false,
"StartWINCC": false,
"Stop": false,
"StopWINCC": false,
"Tag1": true,
"Tag2": false
}
This is the string i want to send to Unity. In Unity3d I've made the following script that used the Concurrentqueue from mono. The script works accordingly, the problem i have however, is that i get alot of null values from the websocket.
my Unity3d script:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Threading;
public class ConcurrentQueue<T> : IEnumerable<T>, ICollection, ISerializable, IDeserializationCallback
{
class Node
{
public T Value;
public Node Next;
}
Node _head = new Node();
Node _tail;
int _count;
/// <summary>
/// </summary>
public ConcurrentQueue()
{
_tail = _head;
}
public ConcurrentQueue(IEnumerable<T> enumerable)
: this()
{
foreach (T item in enumerable)
Enqueue(item);
}
public void Enqueue(T item)
{
var node = new Node { Value = item };
Node oldTail = null;
bool update = false;
while (!update)
{
oldTail = _tail;
var oldNext = oldTail.Next;
// Did tail was already updated ?
if (_tail == oldTail)
{
if (oldNext == null)
{
// The place is for us
update = Interlocked.CompareExchange(ref _tail.Next, node, null) == null;
}
else
{
// another Thread already used the place so give him a hand by putting tail where it should be
Interlocked.CompareExchange(ref _tail, oldNext, oldTail);
}
}
}
// At this point we added correctly our node, now we have to update tail. If it fails then it will be done by another thread
Interlocked.CompareExchange(ref _tail, node, oldTail);
Interlocked.Increment(ref _count);
}
/// <summary>
/// </summary>
/// <returns></returns>
public bool TryDequeue(out T value)
{
value = default(T);
bool advanced = false;
while (!advanced)
{
Node oldHead = _head;
Node oldTail = _tail;
Node oldNext = oldHead.Next;
if (oldHead == _head)
{
// Empty case ?
if (oldHead == oldTail)
{
// This should be false then
if (oldNext != null)
{
// If not then the linked list is mal formed, update tail
Interlocked.CompareExchange(ref _tail, oldNext, oldTail);
}
value = default(T);
return false;
}
else
{
value = oldNext.Value;
advanced = Interlocked.CompareExchange(ref _head, oldNext, oldHead) == oldHead;
}
}
}
Interlocked.Decrement(ref _count);
return true;
}
/// <summary>
/// </summary>
/// <returns></returns>
public bool TryPeek(out T value)
{
if (IsEmpty)
{
value = default(T);
return false;
}
Node first = _head.Next;
value = first.Value;
return true;
}
public void Clear()
{
_count = 0;
_tail = _head = new Node();
}
IEnumerator IEnumerable.GetEnumerator()
{
return InternalGetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return InternalGetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return InternalGetEnumerator();
}
IEnumerator<T> InternalGetEnumerator()
{
Node myHead = _head;
while ((myHead = myHead.Next) != null)
{
yield return myHead.Value;
}
}
void ICollection.CopyTo(Array array, int index)
{
T[] dest = array as T[];
if (dest == null)
return;
CopyTo(dest, index);
}
public void CopyTo(T[] dest, int index)
{
IEnumerator<T> e = InternalGetEnumerator();
int i = index;
while (e.MoveNext())
{
dest[i++] = e.Current;
}
}
public T[] ToArray()
{
T[] dest = new T[_count];
CopyTo(dest, 0);
return dest;
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new NotImplementedException();
}
bool ICollection.IsSynchronized
{
get { return true; }
}
public void OnDeserialization(object sender)
{
throw new NotImplementedException();
}
readonly object _syncRoot = new object();
object ICollection.SyncRoot
{
get { return _syncRoot; }
}
public int Count
{
get
{
return _count;
}
}
public bool IsEmpty
{
get
{
return _count == 0;
}
}
}
public class test : MonoBehaviour
{
class OpcJson
{
public int Index { get; set; }
public bool Moto { get; set; }
public bool Start { get; set; }
public bool StartWINCC { get; set; }
public bool Stop { get; set; }
public bool StopWINCC { get; set; }
public bool Tag1 { get; set; }
public bool Tag2 { get; set; }
}
//variables
static readonly ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
public string receivedFromServer;
WebSocket w = new WebSocket(new Uri("ws://127.0.0.1:8765"));
public Text testert;
public Image moto;
public Image start;
public Image startwincc;
public Image stop;
public Image stopwincc;
public Image tag1;
public Image tag2;
// Use this for initialization
IEnumerator StartWebsocket()
{
yield return StartCoroutine(w.Connect());
//w.SendString("Hi there");
//int i = 0;
while (true)
{
string reply = w.RecvString();
if (reply != null)
{
//Debug.Log(reply);
queue.Enqueue(reply);
//receivedFromServer = reply;
//Debug.Log("Received: " + reply);
//w.SendString("Hi there" + i++);
}
if (w.error != null)
{
Debug.LogError("Error: " + w.error);
break;
}
yield return 0;
}
w.Close();
}
private void OnApplicationQuit()
{
StopAllCoroutines();
w.Close();
}
IEnumerator JsonObjectSetter(float waitforsecods)
{
while (true)
{
queue.TryDequeue(out receivedFromServer);
//string s = receivedFromServer;
//Debug.Log(s);
if(receivedFromServer == null)
{
Debug.Log("I'm null");
}
else
{
var results = JsonConvert.DeserializeObject<OpcJson>(receivedFromServer);
testert.text = results.Index.ToString();
if (results.Moto == true)
{
moto.GetComponent<Image>().color = Color.green;
}
else
{
moto.GetComponent<Image>().color = Color.red;
}
if (results.Start == true)
{
start.GetComponent<Image>().color = Color.green;
}
else
{
start.GetComponent<Image>().color = Color.red;
}
if (results.StartWINCC == true)
{
startwincc.GetComponent<Image>().color = Color.green;
}
else
{
startwincc.GetComponent<Image>().color = Color.red;
}
if (results.Stop == true)
{
stop.GetComponent<Image>().color = Color.green;
}
else
{
stop.GetComponent<Image>().color = Color.red;
}
if (results.StopWINCC == true)
{
stopwincc.GetComponent<Image>().color = Color.green;
}
else
{
stopwincc.GetComponent<Image>().color = Color.red;
}
if (results.Tag1 == true)
{
tag1.GetComponent<Image>().color = Color.green;
}
else
{
tag1.GetComponent<Image>().color = Color.red;
}
if (results.Tag2 == true)
{
tag2.GetComponent<Image>().color = Color.green;
}
else
{
tag2.GetComponent<Image>().color = Color.red;
}
}
yield return new WaitForSeconds(waitforsecods);
}
}
private void Start()
{
StartCoroutine(StartWebsocket());
StartCoroutine(JsonObjectSetter(1));
}
}
as you can see, I've made an if/else statement in my JsonObjectSetter method. Everytime the string is null after a dequeue, it prints out "I'm null", and if its not null, it gets used to set an image to a color according to the value.
How can i make it so I won't get any nulls anymore?
Edit 1: during a 7-minute test I've counted 49 nulls. This is quite a big issue to be honest...
Fixed it!
The problem was that my python script had a time.sleep() which lasts 1 second, changed it to 0.1, and changed the WaitForSecods in the Unityscript to 0.25f. This totally fixed my problem. Kind of stupid that I didn't think of this before posting it on Stackoverflow.

Error: cannot convert from 'lab3.MultiSet' to 'string[]'

MultiSet.cs and Form.cs
The best overloaded method match for 'string.Join(string, string[])' has some invalid arguments
Argument '2': cannot convert from 'lab3.MultiSet' to 'string[]'
namespace lab3
{
internal class MultiSet : IEnumerable<int>
{
public MultiSet()
{
}
public MultiSet(IEnumerable<int> elements)
{
if (elements == null)
throw new ArgumentNullException("elements");
foreach (int element in elements)
Add(element);
}
public MultiSet(params int[] elements)
: this((IEnumerable<int>)elements)
{
}
public IEnumerator<int> GetEnumerator()
{
return new Enumerator(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public bool Add(int element)
{
if (_cardinal == _elements.Length)
{
int[] newElementsArray = new int[_elements.Length * 2];
_elements.CopyTo(newElementsArray, 0);
_elements = newElementsArray;
}
_elements[_cardinal] = element;
_cardinal++;
_lastModificationTime = DateTime.Now;
return true;
}
public int Count
{
get
{
return _cardinal;
}
}
public override string ToString()
{
return string.Format("{{ {0} }}", string.Join(", ", this));
}
private int _cardinal = 0;
private int[] _elements = new int[8];
private DateTime _lastModificationTime = DateTime.Now;
private sealed class Enumerator: IEnumerator<int>
{
public Enumerator(MultiSet set)
{
if (set == null)
throw new ArgumentNullException("set");
_set = set;
_setLastModificationTime = _set._lastModificationTime;
Reset();
}
public int Current
{
get
{
if (_index < 0 || _set._cardinal <= _index || _setLastModificationTime != _set._lastModificationTime)
throw new InvalidOperationException();
return _set._elements[_index];
}
}
void IDisposable.Dispose()
{
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public bool MoveNext()
{
if (_setLastModificationTime != _set._lastModificationTime)
throw new InvalidOperationException();
_index++;
return (_index < _set.Count);
}
public void Reset()
{
_index = -1;
}
private int _index;
private readonly MultiSet _set;
private readonly DateTime _setLastModificationTime;
}
}
}
namespace lab3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
_setElementNumericUpDown.Minimum = int.MinValue;
_setElementNumericUpDown.Maximum = int.MaxValue;
_currentSetTextBox.Text = _currentSet.ToString();
}
private void _addSetButton_Click(object sender, EventArgs e)
{
_setsListBox1.Items.Add(_currentSet);
_setsListBox2.Items.Add(_currentSet);
_currentSet = new MultiSet();
_currentSetTextBox.Text = _currentSet.ToString();
}
private void _addElementToSetButton_Click(object sender, EventArgs e)
{
_currentSet.Add((int)_setElementNumericUpDown.Value);
_currentSetTextBox.Text = _currentSet.ToString();
}
private MultiSet _currentSet = new MultiSet();
}
}
Since your class is an IEnumerable< int >, have you tried making a method that returns a string[] of the items in your list?
private string[] ToStringArray()
{
if (this.Count == 0)
return null;
int i = 0;
string[] items = new string[this.Count];
IEnumerator<int> enumerator = this.GetEnumerator();
while(enumerator.MoveNext())
{
items[i] = enumerator.Current.ToString();
i++;
}
// Reset your enumerator index if needed
enumerator.Reset();
return items;
}
Then your ToString() would look like this:
public override string ToString()
{
return string.Format("{{ {0} }}", string.Join(", ", ToStringArray()));
}

Calculate the sum of the objects in ListNode

How I can make a method to calculate the sum of listOfNodes objects? I was doing with foreach statement like
foreach(int s in listOfNodes)
sum += s;
to get all the nodes but it didn't worked.
It says:
Error 1 foreach statement cannot operate on variables of type 'ConsoleApplication1.Program.List' because 'ConsoleApplication1.Program.List' does not contain a public definition for 'GetEnumerator' C:\Users\TBM\Desktop\I\ConsoleApplication1\ConsoleApplication1\Program.cs 24 13 ConsoleApplication1
My code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List listOfNodes = new List();
Random r = new Random();
int sum = 0;
for (int i = 0; i < 10; i++)
{
listOfNodes.addObjects(r.Next(1, 100));
}
listOfNodes.DisplayList();
Console.ReadLine();
}
class ListNode
{
public object inData { get; private set; }
public ListNode Next { get; set; }
public ListNode(object dataValues)
: this(dataValues, null) { }
public ListNode(object dataValues,
ListNode nextNode)
{
inData = dataValues; Next = nextNode;
}
} // end class ListNode
public class List
{
private ListNode firstNode, lastNode;
private string name;
public List(string nameOfList)
{
name = nameOfList;
firstNode = lastNode = null;
}
public List()//carieli list konstruktori saxelis "listOfNodes"
: this("listOfNodes") { }
public void addObjects(object inItem)
{
if (isEmpty())
{ firstNode = lastNode = new ListNode(inItem); }
else { firstNode = new ListNode(inItem, firstNode); }
}
private bool isEmpty()
{
return firstNode == null;
}
public void DisplayList()
{
if (isEmpty())
{ Console.Write("Empty " + name); }
else
{
Console.Write("The " + name + " is:\n");
ListNode current = firstNode;
while (current != null)
{
Console.Write(current.inData + " ");
current = current.Next;
}
Console.WriteLine("\n");
}
}
}//end of class List
}
}
As the error message says, you need to implement GetEnumerator in order to foreach over something. So, implement GetEnumerator:
public IEnumerator GetEnumerator()
{
ListNode node = firstNode;
while (node != null)
{
yield return node;
node = node.Next;
}
}
You can now have your List class implement the IEnumerable interface too, if you want.
The alternative would be to not use a foreach loop, and instead use a while loop, as I did here, or you did in your DisplayList method.

add indexing to custom list

I have the following list:
public class MyQueue : IEnumerable<int>
{
private Node Head { get; set; }
private Node Tail { get; set; }
public MyQueue()
{
Head = null;
}
public void Add(int item)
{
Enqueue(item);
}
public void Enqueue(int item)
{
var newItem = new Node { Data = item };
if (Head == null)
{
Head = newItem;
Tail = newItem;
return;
}
Node last = Tail;
last.Next = newItem;
Tail = newItem;
}
public IEnumerator<int> GetEnumerator()
{
Node current = Head;
while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private class Node
{
public int Data;
public Node Next;
}
}
There are other methods, but they do not matter in this scenario.
I'd like to add indexing to this list.
So I can do something like:
var q = new MyQueue() {1, 2};
Console.WriteLine(q[0]); //1
What do I need to implement?
you need to make a property like this:
public int this[int index]
{
get {
// code to return value
}
}
public int this[int index]
{
get
{
return this.Skip(index).FirstOrDefault();
}
}
You need to implement an indexer. An indexer enables you to access a class, struct or interface as if it were an array. The syntax is as follows:
public int this[int index] {
get {
// obtain the item that corresponds to this index
// return the item
}
set {
// set the value of the item that corresponds to
// index to be equal to the implicit parameter named "value"
}
}
Here's an explicit example for your case:
public class MyQueue : IEnumerable<int> {
// ...
public int this[int index] {
get {
if (index < 0 || index > this.Count() - 1) {
throw new ArgumentOutOfRangeException("index");
}
return this.Skip(index).First();
}
set {
if (index < 0) {
throw new ArgumentOutOfRangeException("index");
}
Node current = Head;
int i = 0;
while (current != null && i < index) {
current = current.Next; i++;
}
if (current == null) {
throw new ArgumentOutOfRangeException("index");
}
current.Data = value;
}
}
}
Implement the this operator.
Write a this property, like this: (pun intended)
public int this[int index] {
get {
return something;
}
//Optionally:
set {
something = value;
}
}
Also, you should probably implement IList<int>. (Note, though, that the Count property would require a loop)

Categories

Resources