C# Printing ArrayList Containing Multiple Values - c#

I'm new to ArrayList. As far as I know ArrayLists each element(?) can contain multiple values (excuse me for not using the correct terminology).
Now, here's the problem, If I make an ArrayList where each element contains only one value, I can easily print it, however as in the example below, if I attempt to make an ArrayList where each element contains multiple values - I cannot print the values of each element in the ArrayList.
If I try to use foreach or for loop using Console.Writeline(list[i]); all I get is the namespace.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication13
{
class Register
{
public string name;
public string surname;
public void RegisterData()
{
Console.Write("Enter your name: "); name = Console.ReadLine();
Console.Write("Enter your surname: "); surname= Console.ReadLine();
}
public void PrintData()
{
Console.WriteLine("Name: " + name + " Surname: " + surname);
}
}
class Program
{
static void Main(string[] args)
{
ArrayList list = new ArrayList();
Register temp = new Register();
temp.RegisterData();
list.Add(temp);
for (int i = 0; i < list.Count; i++)
{
// How can I use the PrintData (without modifying it) method to print the ArrayList values?
}
}
}
}
How could I be able to print the values of the ArrayList without using the PrintData Method?
Thank you in advance!

ArrayList is .NET 1.1 stuff. You should use List instead. It's generic and superior over ArrayList.
So you define your list like
List<Register> list = new List<Register>();
...
list.Add(temp);
And in the foreach loop, you can access the properties of your Register class. You can do that with ArrayList, too. But then you need casts. Why not use List then... Looks much cleaner:
foreach (Register register in list)
{
Console.WriteLine("Name: " + register.name + " Surname: " + register.surname);
// or
// register.PrintData();
}

You're adding an instance of Register to your ArrayList. When you index into it, list[i], that returns this instance.
When you attempt to print this instance, you are in fact calling this method: Console.WriteLine(object), as it is the best fit. This method needs to get a string from your object, so it calls ToString() on it.
The default implementation of ToString() returns the namespace and type name for the current object. In this case, "WhateverYourBloodyNamespaceIs.Register".
Now you know you have an object of type Register, you can get name and surname from it, format them properly and write those to the console. You've got a PrintData method, use it.
ArrayList isn't generic, so you must cast from object back to Register. Or, be a big boy and use List<Register> instead of that 2002 ArrayList crap.
Whoever told you to use an ArrayList is playing tricks on you.
You need to pick up a copy of CLR Via C#. Skip the first two chapters. Start reading. Go. Run. I'm not joking.

Override ToString() method in your Register class, then you pass the 'temp' variable to Console.WriteLine() method.

Related

Initialization of Array in C# [duplicate]

This question already has answers here:
What is the default value of a member in an array?
(4 answers)
Closed 3 years ago.
I would like to ask some rather basic question (I presume) the answer to which seems to elude me. In the following code I am trying to load an array with a csv file (; separated) that contains two columns (string Name, int Score).
For simplicity I have commented out the loop I want to use to transfer this file onto an array and I am just loading the 2nd element. For some reason unless I use (scoreobj[1] = new HighScore();) I get a null reference.
Why do I need to do that? Haven't I already initialized the scoreobj[] object at the beginning?
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WindowsFormsApp1
{
public class HighScore
{
public string Name { get; set; }
public int Score { get; set; }
public static void LoadHighScores(string filename)
{
string[] scoredata = File.ReadAllLines("C:/Users/User/Desktop/Test.csv");
HighScore[] scoreobj = new HighScore[scoredata.Length];
scoreobj[1] = new HighScore();
scoreobj[1].Name = scoredata[1].Split(';')[0];
//for (int index = 0; index < scoredata.Length; index++)
//{
// scoreobj[index].Name = scoredata[index].Split(',')[0];
// scoreobj[index].Score = Convert.ToInt32(scoredata[index].Split(';')[1]);
//}
Console.WriteLine(scoreobj[1].Name);
}
}
}
Because just declaring an index of a specific size does not create any element of type HighScore,. Instead you just reserve some memory. In other words: just because you have a bag does not put any potatoes in it. You have to go to the market and put potatoes into your bag yourself.
You could even create an instance of a derived class and put it into the exact same array. How would the compiler in this case know which class you want to instantiate?
class Foo { ... }
class Bar { ... }
var array = new Foo[3]; // how would anyone know if you want three Foo-instances or 3 Bar-instances? or a mix?
The compiler can't know which type you want to instantiate and thus won't create those instances. So you have to create the instance yourself.
But even without a derived class, your constructor may have parameters, which compiler can't guess:
class HighScore
{
public HighScore(string name, int score) { ... }
}
var array = new HighScore[3]; // how to set the parameters for the instances???
That's why your object just contains no instances, but just the types default-value, which is null for reference-types.
HighScore[] scoreobj = new HighScore[scoredata.Length]; creates an array of the specified length (scoredata.Length), but containing no objects.
Yo need to assign an object at each index, which could be done as follows:
for (int i = 0; i < scoredata.Length; i++)
{
scoreobj[i] = new HighScore();
scoreobj[i].Name = scoredata[i].Split(';')[0];
}

Create a Generic List Class in C#

I am working on some university material and I Have the following question
Design and implement a collection class dedicated to storing all objects of company
documents as per the class hierarchy, inheriting from any .NET suitable collection class (e.g.
the ArrayList class, or generic List). The collection is to implement a single method
Page 2 of 5
GetDataOfAll() returning a string that concatenates data of all objects with suitable
separators. (The method will later be used to display data in a suitable output placeholder)
I wrote this:
class MainList : List<Document>
{
public string GetDataFormAll()
{
string text = null;
foreach (Document data in MainList)
{
text += data.GetData() + "\n";
}
return text;
}
}
Is this the correct way to implement this?
foreach (Document data in MainList)
This is giving me an error it is telling me that MainList is not of the correct type. How am I to implement this, please.
You need to loop over the Documents in your own (this) collection. Since a List<T> is Enumerable<T>, you can simply write a foreach loop over the this:
public string GetDataFormAll() {
string text = null;
foreach (Document data in this) {
text += data.GetData() + "\n";
}
return text;
}
(Yes, I code like an Egyptian)
Just another and shorter way, not necessarily better
public string GetDataFormAll()
{
return string.Join("\n", this.Select(d => d.GetData());
}
And of course you can shorten it even more with .Select(GetData) syntax.
This will not add a \n after the last element. Depends on what you want.

Save dictionary to text file (C#)

I want to save a dictionary to a text file in Unity3D (using C#). The dictionary contains GameObjects as keys which corresponds to lists of Vector2's.
This is my code:
public void SaveLevel(string LevelName)
{
using (StreamWriter file = new StreamWriter (LevelName+".txt"))
{
foreach (GameObject entity in levelStruct.Keys)
{
file.WriteLine (entity.ToString () + ": " + levelStruct[entity].ToString());
}
}
}
Which produces the example file:
wall (UnityEngine.GameObject): System.Collections.Generic.List`1[UnityEngine.Vector2]
rat (UnityEngine.GameObject): System.Collections.Generic.List`1[UnityEngine.Vector2]
dwarf (UnityEngine.GameObject): System.Collections.Generic.List`1[UnityEngine.Vector2]
floor (UnityEngine.GameObject): System.Collections.Generic.List`1[UnityEngine.Vector2]
My issue is that the file needs to contain the actual items in the Vector2 list, not the list itself:
System.Collections.Generic.List1[UnityEngine.Vector2]
I want the above line to look something like this:
System.Collections.Generic.List1[(0,2),(3,1),(4,3)]
How would i accomplish this?
you can create a varaible of the specific type and get the properties you need
public void SaveLevel(string LevelName)
{
string res;
using (StreamWriter file = new StreamWriter (LevelName+".txt"))
{
foreach (GameObject entity in levelStruct.Keys)
{
foreach(Vector2 v in levelStruct[entity])){
res = " "+"("+v.x+"."+v.y+")";
}
file.WriteLine (entity.ToString () + ": " + res);
}
}
}
I have not used Unity before, so apologies if I have misunderstood. If Vector2 is a custom class that you have created, then you can override the default ToString() method, so that it spits out whichever string you need. Alternatively, you need to access whichever property it is that you're trying to write out from the value in your dictionary. E.g (assuming Foo is your property).
file.WriteLine (entity.ToString() + ": " + levelStruct[entity].Foo.ToString());
I think you should use serializing and deserializing to save and recover your objects, because when you use ToString() function return just the name of object in most of times. I suggest you to google it but there is some resources:
http://www.codeproject.com/Articles/483055/XML-Serialization-and-Deserialization-Part
https://msdn.microsoft.com/en-us/library/58a18dwa(v=vs.110).aspx
You are writing objects. When you call a ToString() on an object, you get the name of the object type. Instead, you need to do one of two things:
#1: If you really want to write using CSV as your code suggests:
Object.Property.ToString();
In the case of a GameObject, you might need to use reflection to do this
using System.Reflection;
foreach(PropertyInfo p in typeof(UnityEngine.GameObject).GHetProperties()){
Console.WriteLine(p.Name+","+p.GetType().ToString());
}
//repeat as necessary with fields and methods and ... as needed using System.Reflection
The second item is a list of vectors - same thing. For that, you'd use
foreach(UnityEngine.Vector2 vect in levelStruct[entity])){
//write ToString();
}
#2: Learn how to serialize object to XML or Json and save then that way:
https://www.google.com/search?q=c-sharp+how+to+serialize+objects+into+json&ie=&oe=
Good luck - if you get stuck on something specific just ask.

Retrieving Anonymous Object's Property in C#

I have the following code
using System;
using System.Collections.Generic;
public class Test
{
public static void Main()
{
List<object> list = new List<object>();
list.Add(new {
Value = 0
});
//Console.WriteLine(list[0].Value);
}
}
Is there a simple way to write the commented line of code without causing a compile time error? I know I could resort to using the dynamic keyword or implementing an extension method for the Object class that uses Reflection, but is there maybe another more acceptable way?
The goal is the avoid creating a class since its only purpose would be to store data. But at the same time still be able to retrieve the data later on in the program. This code will eventually end up in a web method which is why I want it to be dynamic / anonymous in the first place. All of the objects would end up having the same properties, as they would be storing values stored in tables, but the values are needed later for other calculations.
Is there a simple way to write the commented line of code without causing a compile time error?
Not with the way you've declared the list. If your list will contain only objects of that anonymous type, you could use an array initializer and convert it to a List<{anonymous type}>:
var list = (new [] {
new { Value = 0 }
}).ToList();
Console.WriteLine(list[0].Value);
The nice thing is that you can add to the list easily, since anonymous types with the same properties are merged into one type by the compiler:
list.Add(new {Value = 1});
Per Servy's comment, a method to avoid an array creation would just be:
public static List<T> CreateList<T>(params T[] items)
{
return new List<T>(items);
}
usage:
var list = CreateList(new { Value = 0 });

Recursive problem

I need compare file names with user input and have to display the files that are matching. I am using a recursive function for that.I stored the matched files in a list.But I got problems when I return the list. How to return values from a function which is called recursively?
You can 'return' data using parameters. For example:
public void MyRecursiveFunction(List<string> files, int depth)
{
files.Add("...");
if (depth < 10)
{
MyRecursiveFunction(files, depth + 1);
}
}
Option 1 (better approach):
You can pass a string to the recursive method, append the filename with a comma to the string inside the recursive function and pass the same string when the recursive function is called from within itself. Better option would be to use a StringBuilder rather than a string.
Option 2 (not recommended):
You might want to declare a global variable have the function append data to it.
In both the options you could use a List<> if more appropriate.
It's trivial; you set an exit case:
function f (List m){
if( y )
{
m.Add(k);
return f(m);
}
return m;
}
Pass the list in as a param. All classes are 'pointers' so when its modified inside the func the changes appears everywhere. If i didnt answer your question heres something i written a few days ago.
oops, this doesnt show passing a list around. However you essentially doing the below but with a list instead of an int? pass the list as a param. Also you can lookup the ref keyword but thats not necessary.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace DeleteWhenBelow
{
class Program
{
static void Main(string[] args)
{
var dir = #"C:\Users\FixLoc\Documents\";
var count = findAndDelete(dir, false, 1);
Console.WriteLine(count);
}
static long findAndDelete(string folder, bool recurse, long filesize)
{
long count = 0;
if(recurse)
{
foreach (var d in Directory.GetDirectories(folder))
{
count += findAndDelete(d, recurse, filesize);
}
}
foreach (var f in Directory.GetFiles(folder))
{
var fi = new FileInfo(f);
if (fi.Length < filesize)
{
File.Delete(f);
count++;
}
}
return count;
}
}
}
Since you are using C# 3.0, you could use LINQ to simplify your problem:
var expectedNames = getExpectedFilenames();
var matchingFiles = directoryInfo
.GetFileSystemInfos()
.SelectMany(fsi => fsi.GetFileSystemInfos())
.OfType<FileInfo>()
.Where(fi => expectedNames.Contains(fi.Name));
I have not tested the above code, so it might need some tweaking... The GetFileSystemInfos will get both DirectoryInfo and FileInfo objects, then project the same operation onto each returned entry with SelectMany. SelectMany will flatten the hierarchical structure. OfType filters out directories. The Where searches the set of expected file names against each file name from your projection.

Categories