Linked List/Node Clas - Adding User Input to Linked List - c#

I have the user inputting a string which is stored in the variable 'word'. I now want to add this stored variable to the linked list. I've tried using
LinkedList<string>.Add(word);
To add the variable to the linked this but it isn't working and is returning the error "An object reference is required for the non-static field, method or property 'LinkedList.Add(string)"
I'm assuming it has something to do with my linked list but I'm not to sure.
Any help or ideas on the issue would be great.
using System;
using System.Collections.Generic;
using System.Text;
namespace project
{
public class LinkedList<TData>
{
private Node<TData> head;
private int count;
public LinkedList(string word)
{
this.head = null;
this.count = 0;
}
public bool Empty
{
get { return this.count == 0; }
}
public int Count
{
get { return this.count; }
}
public TData this[int index]
{
get { return this.Get(index); }
}
public TData Add(int index, TData data)
{
if (index < 0)
throw new ArgumentOutOfRangeException("Index: " + index);
if (index > count)
index = count;
Node<TData> current = this.head;
if (this.Empty || index == 0)
{
this.head = new Node<TData>(data, this.head);
}
else
{
for (int i = 0; i < index - 1; i++)
{
current = current.Next;
current.Next = new Node<TData>(data, current.Next);
}
}
count++;
return data;
}
public TData Add(TData data)
{
return this.Add(count, data);
}
public TData Remove(int index)
{
if (index < 0)
throw new ArgumentOutOfRangeException("Index: " + index);
if (this.Empty)
return default(TData);
if (index >= this.count)
index = count - 1;
Node<TData> current = this.head;
TData result;
if (index == 0)
{
result = current.Data;
this.head = current.Next;
}
else
{
for (int i = 0; index < index - 1; i++) ;
current = current.Next;
result = current.Next.Data;
current.Next = current.Next.Next;
}
count--;
return result;
}
public void Clear()
{
this.head = null;
this.count = 0;
}
public int IndexOf(TData data)
{
Node<TData> current = this.head;
for (int i = 0; i < this.count; i++)
{
if (current.Data.Equals(data))
return i;
current = current.Next;
}
return -1;
}
public bool Contains(TData data)
{
return this.IndexOf(data) >= 0;
}
public TData Get(int index)
{
if (index < 0)
throw new ArgumentOutOfRangeException("Index: " + index);
if (this.Empty)
return default(TData);
if (index >= this.count)
index = this.count - 1;
Node<TData> current = this.head;
for (int i = 0; i < index; i++)
current = current.Next;
return current.Data;
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace project
{
public class Node<TData>
{
private Node<TData> next { get; set; }
public Node(TData data, Node<TData> next)
{
this.Data = data;
this.next = next;
}
public TData Data { get; set; }
public Node<TData> Next
{
get { return this.next; }
set { this.next = value; }
}
}
}
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace project
{
class Program
{
static void Main(string[] args)
{
string word;
Console.WriteLine("Please enter a word");
word = Console.ReadLine();
Console.WriteLine("You typed: " + word);
Console.ReadKey();
var list = new LinkedList<string>(word);
LinkedList<string>.Add(word);
}
}
}

Change this:
var list = new LinkedList<string>(word);
LinkedList<string>.Add(word);
To this:
var list = new LinkedList<string>();
list.Add(word);
list is your linked list object in memory. Whenever you want to do something with your list, you use the variable reference list, not the name for the kind of object it is. The reason we use the name of the variable rather than the name of the kind is because we might very well want to have two or more of them in our program:
var postiveList = new LinkedList<string>();
var negativeList = new LinkedList<string>();
positiveList.Add("happy");
negativeList.Add("sad");
It's only possible to use the name of the type(kind), when you're using something declared as static - and nothing in your program is static that I can point to and make a suitable demonstration of. Something you'll have probably used though:
int x = Convert.ToInt32("1234");
Convert here is static, the name of a type of class. You don't need to make a new Convert before you use it, and you can't have (nor need) more than one Convert in a program, so it makes sense to have it be static (only one of them)
Some things are both static and not:
var startTime = new DateTime(1970,1,1);
var endTime = DateTime.UtcNow;
startTime and endTime are both instances of a DateTime. To get the end time, however, we used a static property UtcNow of the DateTime type. It created a new DateTime for us based on the value of the computer clock and returned it. We didn't need for any other datetime to exist before we did this. If it helps, think of these static things as being like factories that churn out manufactured objects on demand. There is only one factory, and the things it makes are always the same kind of thing but it can make millions of them
Also change this:
public LinkedList(string word)
{
this.head = null;
this.count = 0;
}
To this:
public LinkedList()
{
this.head = null;
this.count = 0;
}
There's no point asking for something and then not doing anything with it - it just makes the thing that asks harder to use. I get the feeling you didn't write LinkedList, but you might have added this in while trying to get a word into it

you write:
LinkedList<string>.Add(word);
This is an attempt to call a static method Add on the type LinkedList<string>. And the compiler is telling you that this is a instance method and not a static method. I.e. you want to call:
list.Add(word);
Also, the constructor
public LinkedList(string word)
takes a string, but does not do anything with it. This parameter should probably be removed.

Related

How to get Next and Previous values of Enumerator List?

When am trying to while loop of Enumerator List, How to get Next and previous values. Please find the below code.
public static void Main()
{
List<string> mylist = new List<string>();
mylist.Add("C#");
mylist.Add("Java");
mylist.Add("C");
mylist.Add("C++");
// To get an Enumerator
// for the List.
List<string>.Enumerator em = mylist.GetEnumerator();
display(em);
}
static void display(IEnumerator<string> em)
{
while (em.MoveNext()) {
string val = em.Current; // Want to know Next and Previous values of current value.
Console.WriteLine(val);
}
}
Enumerators, in the GetEnumerator() sense, are forwards-only, once-only cursors over data. If you want to know the next value: use MoveNext() and look. If you want to know what the previous value was: you should have remembered it. Since most data structures are not doubly-linked lists, and since enumerators are not even necessarily based on data that is stored anywhere (you can do some really interesting things with iterator blocks), nothing else is possible.
In the specific case of List<T>: perhaps use a for loop instead of your foreach-like enumerator access, and then you can just use list[i-1] and list[i+1] (after checking your boundary conditions).
Note: as a general rule, you should avoid using the enumerator APIs directly unless you are very, very familiar with what is going on underneath. Prefer foreach or indexer-based access.
You could generalize a triplet (previous/current/next) iterator with your own iterator block; the output from { 1, 4, 5, 1, 543, 2, 1, 54, 23 }
is:
1-4-5
4-5-1
5-1-543
1-543-2
543-2-1
2-1-54
1-54-23
Code:
using System;
using System.Collections.Generic;
public static class Program
{
static void Main()
{
var data = new List<int> { 1, 4, 5, 1, 543, 2, 1, 54, 23 };
foreach(var t in data.Tripletize())
{
Console.WriteLine($"{t.Previous}-{t.Current}-{t.Next}");
}
}
static IEnumerable<Triplet<T>> Tripletize<T>(this IEnumerable<T> source)
{
using (var iter = source.GetEnumerator())
{
// read the first triple
if (!iter.MoveNext()) yield break;
var x = iter.Current;
if (!iter.MoveNext()) yield break;
var y = iter.Current;
if (!iter.MoveNext()) yield break;
var z = iter.Current;
yield return new Triplet<T>(x, y, z);
while (iter.MoveNext())
{
x = y;
y = z;
z = iter.Current;
yield return new Triplet<T>(x, y, z);
}
}
}
readonly struct Triplet<T>
{
public Triplet(T previous, T current, T next)
{
Previous = previous;
Current = current;
Next = next;
}
public T Previous { get; }
public T Current { get; }
public T Next { get; }
}
}
IEnumerable does not support checking the previous and next items. It provides access only to the current item. If you want to track the previous item you should store it manually in a local variable. Or you should store two previous values and pretend that the current one is the next.
static void display(IEnumerator<string> em)
{
if (!em.MoveNext())
return;
string prev = null; // store prev
string current = null; // store current
string next = em.Current; // null <- null -> next
do
{
// move 'window' further so that next becomes current
prev = current;
current = next;
next = em.MoveNext() ? em.Current : null;
Console.WriteLine($"[{prev}] <-[{current}]-> [{next}]");
}
while (next != null);
}
Output with your test data:
"[] <-[C#]-> [Java]"
"[C#] <-[Java]-> [C]"
"]Java] <-[C]-> [C++]"
"[C] <-[C++]-> []"
But there is a data type with required functionality from the box - doubly linked list
var mylist = new LinkedList<string>(); // instead of List
mylist.AddLast("C#");
mylist.AddLast("Java");
mylist.AddLast("C");
mylist.AddLast("C++");
display(mylist );
And here you go
static void display(LinkedList<string> list)
{
var current = list.First;
while (current != null)
{
string val = current.Value;
// null if there is no next/prev value, but you can just check if node exists
string prev = current.Previous?.Value;
string next = current.Next?.Value;
Console.WriteLine(val);
current = current.Next;
}
}
Use Something like this :
class Program
{
int position = -1;
public List<string> mylist;
public bool MoveNext()
{
position++;
return (position < mylist.Count);
}
public String GetCurrent
{
get
{
return Current;
}
}
public string GetPrevious
{
get
{
return Previous;
}
}
public String Previous
{
get
{
try
{
return mylist[position-1];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
public String Current
{
get
{
try
{
return mylist[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
void Main(string[] args)
{
mylist = new List<string>();
mylist.Add("C#");
mylist.Add("Java");
mylist.Add("C");
mylist.Add("C++");
display(mylist);
}
void display(List<string> em)
{
while (MoveNext())
{
string val = GetCurrent;
string val2 = GetPrevious;
Console.WriteLine(val);
}
}
}

Xceed.Words.NET DocX - Add document to Maindocument and reset Numbered lists to 1

Good day,
I try that when I connect two documents, the numbered lists are reset. As in the example below.
I use the Xceed.Words.NET DocX libary.
In this Sample, the Template is :
Test Header
List:
1) <-This should be one
And the Result is:
Test Header
List:
1) <-This should be one
Test Header
List:
2) <-This should be one
Test Header
List:
3) <-This should be one
With the following code I am able to create the lists with similar formatting, but the formatting does not match 100%. Does anyone have any idea which way to try otherwise?
Note the number of existing paragraphs and call the function to reset the list after inserting the document.
/// <summary>
/// Insert complete WordFile
/// </summary>
/// <param name="wordFile"></param>
public void InsertWordTemplate(IWordFile wordFile, bool InsertPageBreak)
{
if (wordFile != null && wordFile.IsFileOk)
{
int pargraphCount = Document.Paragraphs.Count - 1;
// NotNeeded for this Problem wordFile.RemoveStyles();
// NotNeeded for this Problem RemoveHeaderAndFooter(wordFile);
Document.InsertDocument(wordFile.Document);
// NotNeeded for this Problem ReplaceSectionBreak(InsertPageBreak, pargraphCount);
ResetNumberedList(pargraphCount);
logger.Info("Word file inserted: " + wordFile.File.FullName);
}
else
{
logger.Warn("Word file is not okay - will not be inserted: " + wordFile?.File?.FullName);
}
}
In the Word document, three different names are used in a list, only from the 4th level is worked with a level. For other Word templates they are called different.
private void ResetNumberedList(int pargraphCount)
{
string styleName1 = "ListNumbers";
string styleName2 = "PIgeordneteListe2Ebene";
string styleName3 = "PIgeordneteListe3Ebene";
NumberedListReset numberedListReset = new NumberedListReset(Document, styleName1, styleName2, styleName3);
bool OnlyFirstFoundList = true;
numberedListReset.Reset(pargraphCount, OnlyFirstFoundList);
}
Below is the helper class with which I try to reset the numbering. I do this by myself
I notice the formatting of the individual list items, create new lists, fill them with the old values, set the styles correctly again and then insert everything into old place.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Xceed.Document.NET;
using Xceed.Words.NET;
namespace PIB.Report.DataWriter.WordExport
{
public class NumberedListReset
{
private readonly DocX _Document;
private readonly string _StyleName1;
private readonly string _StyleName2;
private readonly string _StyleName3;
public NumberedListReset(DocX Document, string StyleName1, string StyleName2, string StyleName3)
{
_Document = Document;
_StyleName1 = StyleName1;
_StyleName2 = StyleName2;
_StyleName3 = StyleName3;
}
public void Reset(int StartParagraphNumber, bool OnlyFirstFinding)
{
for (int i = StartParagraphNumber; i < _Document.Paragraphs.Count; i++)
{
var paragraph = _Document.Paragraphs[i];
if (paragraph.IsListItem == true && paragraph.ListItemType == ListItemType.Numbered && paragraph.StyleName == _StyleName1)
{
//int? numId = GetNumId(paragraph);
//if (numId != -1)
//{
//}
ResetFoundList(ref i);
if (OnlyFirstFinding == true)
{
break;
}
}
}
}
private void ResetFoundList(ref int ParagraphCounter)
{
List<ParagraphMemorize> ParagraphMemorizes = CreateMemorizeListItems(ParagraphCounter);
if (ParagraphMemorizes.Count != 0)
{
RemoveOldParagraphsFromDocument(ParagraphMemorizes);
List numberedList = CreateNewDocumentList();
FillDocumentList(ParagraphMemorizes, numberedList);
List<Paragraph> actualListData = numberedList.Items;
ResetSyleNames(ParagraphMemorizes, actualListData);
InsertNewParagraphsToDocument(ParagraphCounter, actualListData);
ParagraphCounter += ParagraphMemorizes.Count;
}
}
private List<ParagraphMemorize> CreateMemorizeListItems(int ParagraphCounter)
{
List<ParagraphMemorize> ParagraphMemorizes = new List<ParagraphMemorize>();
for (int ii = ParagraphCounter; ii < _Document.Paragraphs.Count; ii++)
{
var paragraph = _Document.Paragraphs[ii];
if (!NameIsKnown(paragraph.StyleName))
{
break;
}
ParagraphMemorize paragraphMemorize = new ParagraphMemorize(paragraph);
paragraphMemorize.ListLevel = GetListLevel(paragraph);
ParagraphMemorizes.Add(paragraphMemorize);
}
return ParagraphMemorizes;
}
private void RemoveOldParagraphsFromDocument(List<ParagraphMemorize> ParagraphMemorizes)
{
ParagraphMemorizes.ForEach(m => _Document.RemoveParagraph(m.Paragraph));
}
private List CreateNewDocumentList()
{
return _Document.AddList(startNumber: 1);
}
private void FillDocumentList(List<ParagraphMemorize> ParagraphMemorizes, List numberedList)
{
for (var ii = 0; ii < ParagraphMemorizes.Count; ii++)
{
//numberedList.AddItem(ParagraphMemorizes[ii].Paragraph); //Raised an Error
ParagraphMemorize paragraphMemorize = ParagraphMemorizes[ii];
int listLevel = GetListLevel(paragraphMemorize);
_Document.AddListItem(numberedList, paragraphMemorize.Text, listLevel);
}
}
private static void ResetSyleNames(List<ParagraphMemorize> ParagraphMemorizes, List<Paragraph> actualListData)
{
for (int ii = 0; ii < actualListData.Count; ii++)
{
actualListData[ii].StyleName = ParagraphMemorizes[ii].StyleName;
}
}
private void InsertNewParagraphsToDocument(int i, List<Paragraph> actualListData)
{
Paragraph paragraph = _Document.Paragraphs[i];
for (int ii = 0; ii < actualListData.Count; ii++)
{
paragraph.InsertParagraphBeforeSelf(actualListData[ii]);
}
}
private bool NameIsKnown(string Name)
{
return Name == _StyleName1 | Name == _StyleName2 | Name == _StyleName3;
}
private int GetListLevel(ParagraphMemorize paragraphMemorize)
{
if (paragraphMemorize.StyleName == _StyleName1)
{
return 0;
}
else if (paragraphMemorize.StyleName == _StyleName2)
{
return 1;
}
else if (paragraphMemorize.StyleName == _StyleName3)
{
return (int)paragraphMemorize.ListLevel;
}
else
{
return 0;
}
}
private int? GetNumId(Paragraph paragraph)
{
var numIds = paragraph.ParagraphNumberProperties.Descendants().Where(e => e.Name.LocalName.Equals("numId"));
foreach (var numId in numIds)
{
XNamespace nsW = Namespace.WordNamespace;
var values = numId.Attributes(XName.Get("val", nsW.ToString()));
foreach (var value in values)
{
int resultId = 0;
int.TryParse(value.Value, out resultId);
return resultId;
}
}
return null;
}
private int? GetListLevel(Paragraph paragraph)
{
var numIds = paragraph.ParagraphNumberProperties.Descendants().Where(e => e.Name.LocalName.Equals("ilvl"));
foreach (var numId in numIds)
{
XNamespace nsW = Namespace.WordNamespace;
var values = numId.Attributes(XName.Get("val", nsW.ToString()));
foreach (var value in values)
{
int resultId = 0;
int.TryParse(value.Value, out resultId);
return resultId;
}
}
return null;
}
private class ParagraphMemorize
{
public Paragraph Paragraph { get; set; }
public string Text { get; set; }
public string StyleName { get; set; }
public int? ListLevel { get; set; }
public ParagraphMemorize(Paragraph Paragraph)
{
this.Paragraph = Paragraph;
this.Text = Paragraph.Text;
this.StyleName = Paragraph.StyleName;
}
}
}
}

Access updated array from constructor

I have a parameterized constructor and a default constructor. They both create a new object array with x length, however, when I try to access the array in the Add method, it returns the value "null". I can't initialize the array in the fields because I don't know what size the user wants it to be, but I don't know how to access the 'updated' array later in the code. I get a NullReferenceException() on the line of code: if (count > data.Length) because data has the value null.
class CustomList
{
private int count;
private String[] data;
public int Count
{
get { return count; }
}
public CustomList(int arrayNum)
{
String[] data = new String[arrayNum];
}
public CustomList(): this(4)
{
}
public void Add (String item)
{
if (count > data.Length)
{
String[] temp = new String[count * 2];
for (int i = 0; i < data.Length; i++)
{
temp[i] = data[i];
}
data = temp;
}
data[count] = item;
count++;
}
Change this:
public CustomList(int arrayNum)
{
String[] data = new String[arrayNum];
}
To this:
public CustomList(int arrayNum)
{
data = new String[arrayNum];
}
You have accidentally created a local variable in the constructor which is being assigned to instead of the field that you wanted to assign to.
Change your code.
Your data object in constructor is local variable.
And you are not initializing your instance data object.
class CustomList
{
private int count;
private String[] data;
public int Count
{
get { return count; }
}
public CustomList(int arrayNum)
{
data = new String[arrayNum];
}
public CustomList(): this(4)
{
}
public void Add (String item)
{
if (count > data.Length)
{
String[] temp = new String[count * 2];
for (int i = 0; i < data.Length; i++)
{
temp[i] = data[i];
}
data = temp;
}
data[count] = item;
count++;
}

Trying to figure out why my project is not running right

My program reads from a text file delimited with a comma. The answers are an array of strings which I can't get to populate at the console.
The Question will show up, the correct Answer(a single char) will show up and the explanation will show up, it is just the array with the answers I am having problems with.
I will supply the code below.
The Question Unit( Structure of the Questions from the text file)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HoodTalkTrivia
{
class QuestionUnit
{
private string correctAnswer;
private string explanation;
private string question;
private string[] answer = new string[4];
public string CorrectAnswer
{
get { return correctAnswer; }
set { correctAnswer = value; }
}
public string Explanation
{
get { return explanation; }
set { explanation = value; }
}
public string Question
{
get { return question; }
set { question = value; }
}
public string[] Answer
{
get {return answer; }
set { answer = value; }
}
}
}
The Question Bank
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace HoodTalkTrivia
{
class QuestionBank
{
List<QuestionUnit> theQuestionsList = new List<QuestionUnit>();
// private string[] Questions;
const int NUM_ANSWERS = 4;
const int NUM_QUESTIONS = 5;
public int GetNumberOfAnswers
{
get { return NUM_ANSWERS; }
}
public int GetNumberOfQuestions
{
get { return NUM_QUESTIONS; }
}
public string GetCorrectAnswer(int index)
{
return theQuestionsList[index].CorrectAnswer;
}
public string GetExplanation(int index)
{
return theQuestionsList[index].Explanation;
}
public string GetQuestion(int index)
{
return theQuestionsList[index].Question;
}
public string[] GetAnswer(int index)
{
return theQuestionsList[index].Answer;
}
public bool ReadQuestionFile()
{
bool success = true;
FileInfo httSourceFile = new FileInfo("Questions.txt");
string line;
string[] fields;
char[] delimiter = { System.Convert.ToChar(",") };
QuestionUnit httQuestionUnit;
//int i = 0;
try
{
StreamReader httReader = httSourceFile.OpenText();
line = httReader.ReadLine();
while (line != null)
{
httQuestionUnit = new QuestionUnit();
fields = line.Split(delimiter);
httQuestionUnit.Question = fields[0];
string[] aArray = new string[4];
aArray[0] = fields[1];
aArray[1] = fields[2];
aArray[2] = fields[3];
aArray[3] = fields[4];
httQuestionUnit.Answer = aArray;
httQuestionUnit.CorrectAnswer = fields[5];
httQuestionUnit.Explanation = fields[6];
theQuestionsList.Add(httQuestionUnit);
line = httReader.ReadLine();
}
}
catch
{
success = false;
}
return success;
}
}
}
And the main
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HoodTalkTrivia
{
class HoodTalkTriviaGame
{
HoodTalkTriviaStrings myGameStrings;
public void PlayAgain()
{
}
public void Play()
{
QuestionBank myQuestions = new QuestionBank();
DisplayWelcome();
myQuestions.ReadQuestionFile();
for (int i = 0; i < myQuestions.GetNumberOfQuestions; i++)
{
Console.WriteLine(myQuestions.GetQuestion(i));
for (int j = 0; j < myQuestions.GetNumberOfAnswers; j++)
{
Console.WriteLine(myQuestions.GetAnswer(j));
}
// Console.WriteLine(myQuestions.GetCorrectAnswer(i));
Console.WriteLine("Make a selection, A - D");
Console.ReadLine();
}
}
public void DisplayWelcome()
{
myGameStrings = new HoodTalkTriviaStrings();
myGameStrings.WelcomeString();
}
public char PromptForGuess()
{
char guess = ' ';
return guess;
}
}
}
Here is an image of what i am getting at the console.
GetAnswer method returning an array of strings, so you are seeing the name of the type of your array in the console instead of the contents.
You can change your code like this:
Change this code:
for (int j = 0; j < myQuestions.GetNumberOfAnswers; j++)
{
Console.WriteLine(myQuestions.GetAnswer(j));
}
To:
var answers = myQuestions.GetAnswer(i);
for (int j = 0; j < answers.Length; j++)
{
Console.WriteLine(answers[j]);
}
Then you should see the answers of your question in the console.
You need to use the second index for the possible answers, because Answer is an array again:
for (int j = 0; j < myQuestions.GetNumberOfAnswers; j++)
{
Console.WriteLine(myQuestions.GetAnswer(i)[j]);
}
An alternative way of solving the problem is to change the acessor method:
public string GetAnswer(int questionIndex, int answerIndex)
{
return theQuestionsList[questionIndex].Answer[answerIndex];
}
And then the loop will be:
for (int j = 0; j < myQuestions.GetNumberOfAnswers; j++)
{
Console.WriteLine(myQuestions.GetAnswer(i, j));
}
Now the signature of the GetAnswer makes it impossible to forget the second index. It would also be helpful to rename the Answer property to Answers. This would remind you that an array is returned.
I think your solution a bit over-designed. An overall simplified approach would make it easier to use the classes. If the QuestionBank simply had a property returning an enumeration of question units this would be enough. No need for all the GetXYZ methods.
class QuestionBank
{
List<QuestionUnit> theQuestionsList = new List<QuestionUnit>();
public IEnumerable<QuestionUnit> Questions { get { return theQuestionsList; } }
...
}
Returning an IEnumerable<QuestionUnit> has the advantage over returning a List<QuestionUnit> that the real type of the question list is not made public, thus allowing you to change the implementation at any time without invalidating any code that accesses the questions from the outside.
Then the loops will become easier:
foreach (QuestionUnit questionUnit in myQuestions)
{
Console.WriteLine(questionUnit.Question);
foreach (string answer in questionUnit.Answers)
{
Console.WriteLine(answer);
}
Console.WriteLine("Make a selection, A - D");
Console.ReadLine();
}

Null Reference Exception was unhandled C# console application

I know this is probably similar to some other posts, but I'm not quite sure what I'm doing wrong here. As an FYI, I'm new to programming and still trying to learn proper flow.
Here is the code, the exception occurs at "MyFriends[i].Name = friendName".
using System;
using System.Collections;
namespace FriendList
{
class FriendList
{
static public Friend[] MyFriends = new Friend[2];
public static void Main()
{
string friendName;
string friendPhone, friendMonth, friendDay, friendYear;
int intMonth, intDay, intYear;
for (int i = 0; i < 2; ++i)
{
Console.Write("enter name");
friendName = Console.ReadLine();
MyFriends[i].Name = friendName;
Console.Write("phone");
friendPhone = Console.ReadLine();
MyFriends[i].Phone = friendPhone;
Console.WriteLine("Enter Month: ");
friendMonth = Console.ReadLine();
intMonth = Convert.ToInt32(friendMonth);
MyFriends[i].Month = intMonth;
Console.WriteLine("Enter Day: ");
friendDay = Console.ReadLine();
intDay = Convert.ToInt32(friendDay);
MyFriends[i].Day = intDay;
Console.WriteLine("Entery Year: ");
friendYear = Console.ReadLine();
intYear = Convert.ToInt32(friendYear);
MyFriends[i].Year = intYear;
}
for (int i = 0; i < 2; ++i)
{
string information = string.Format("first name: {0}, phone {1}", MyFriends[i].Name, MyFriends[i].Phone);
Console.WriteLine(information);
}
Console.Read();
}
}
class Friend
{
string _Name = string.Empty, _Phone = string.Empty;
int _Day = 0, _Month = 0, _Year = 0;
public string Name
{
get { return _Name; }
set { _Name = value; }
}
public string Phone
{
get { return _Phone; }
set { _Phone = value; }
}
public int Month
{
get { return _Month; }
set { _Month = value; }
}
public int Day
{
get{ return _Day; }
set{ _Day = value ; }
}
public int Year
{
get { return _Year;}
set { _Year = value; }
}
public Friend()
{ }
}
}
Thank you for your guidance!
Your friend array is initialized empty. So MyFriends[i] will hit a null reference, which is another way to say you are trying to access something that doesn't exist.
In other words, you have an Array with slots for two friends, but both slots are empty. You still need to have a friend in each slot before you can use their properties, such as Name, Phone etc.
Simply start the for loop like this:
for (int i = 0; i < 2; ++i)
{
MyFriend[i] = new Friend(); //or pass parameters as required by the constructor
// rest of your code goes here
}
And things will be fine. This way, you are adding a friend to the slot you will be using.
You've created an array with two elements, but you have set the elements to any value. They are both null:
static public Friend[] MyFriends = new Friend[2];
So, when you try to use MyFriends[i] from the array, you're actually getting null.
MyFriends[i].Name = friendName;
That where your NullReferenceException came from.
You'll have to initialize the members of the array. For example:
for (int i = 0; i < MyFriends.Length; i++)
{
// Put a new Friend object in the array.
MyFriends[i] = new Friend();
// ...
When creating collections, they're populated with default values of the target type, and the default value for any reference type if null. So to solve your problem you'd have to initialize items in the array before accessing them:
....
for (int i = 0; i < 2; ++i)
{
MyFriends[i] = new Friend();
...
MyFriends is an array of Friend class.
each element in the array needs to be initialized with a friend constructor so it will be allocated with a memory.

Categories

Resources