I'm trying to loop through an array of objects and print their properties from a different class.
My main class is
class Program
{
static void Main()
{
//This to be change to relative path
string Path = #"C:\Users\";
string[] lines = { }; ;
//Reading file
if (File.Exists(Path))
{
lines = File.ReadAllLines(Path);
StudentReport.ReadStudents(lines);
}
else
{
Console.WriteLine("The file does't exist");
}
//Printing Students
PrintStudent.Print(lines.Length);
}
}
I'm using this code to declare the array
public class StudentReport
{
public static void ReadStudents(string[] Lines)
{
//declare an array with the number of students
Student[] studentArray = new Student[Lines.Length];
int StudentCounter = 0;
foreach (string Line in Lines)
{
String[] Student = Line.Split(',');
//Calculating values
string ID = Student[0].PadLeft(10, '0');
string name = Student[1];
//Initialize the object
studentArray[StudentCounter] = new Student
{
FullName = name,
ID = ID,
};
StudentCounter++;
}
}
}
And I'm using this class to construct my student object
class Student
{
public string FullName { get; set; }
public string ID { get; set; }
}
To output the student object properties, I made another class. The problem is that I couldn't access the value of the objects array from my new class.
The class I made for outputting purposes is the following, but I cannot get the values. The error is 'Student does not contain a definition for student array
public class PrintStudent
{
public static void Print(int StudentCounter)
{
for(int i = 0; i > StudentCounter; i++)
{
Console.WriteLine(Student.studentArray[i].FullName);
}
}
}
Your error is Student does not contain a definition for studentArray. This is because your Student class does not have studentArray, only the properties FullName and ID. So accessing Student.studentArray[i] doesn't make sense.
Probably what you want is for ReadStudents to return the studentArray so it doesn't go out of scope by changing the method signature to return the Student[], and calling return studentArray at the end.
Then, you can pass your studentArray to your PrintStudent.Print method in the parameters.
By the way, the for(int i = 0; i > StudentCounter; i++) has a wrong < and will never run (lines.Length which is the StudentCounter will always be >= 0)
You can use studentArray.Length, or a foreach loop to iterate over this array, rather than pass the StudentCounter.
Related
UML is attached. I want to create a readonly property of pre which is an array of string. When I create an object in the main and try to set name and pre it is showing me an error.
UML
using System;
class Unit
{
private string _name;
private string[] _pre;
public Unit(string name, string[] pre)
{
_name = name;
_pre = new string[2];
}
public string Name { get { return _name; } }
public string[] Pre { get { return _pre; } }
}
class Program
{
public static void DisplayInfo(Unit[] _u)
{
for (int i = 0; i < 2; i++)
{
Console.WriteLine(_u[i].Name + _u[i].Pre);
}
}
static void Main(string[] args)
{
Unit[] unitarraytest = new Unit[2];
unitarraytest[0] = new Unit("test 1", "test 3");
unitarraytest[1] = new Unit("test 2", "test 4");
DisplayInfo(unitarraytest);
}
}
Your example makes little sense. You Unit constructor takes a parameter for "Pre", but immediately throws it away and allocates a new empty string array instead. It should probably be written like
class Unit
{
public Unit(string name, string[] pre)
{
Name = name;
Pre = pre;
}
public string Name { get;}
public string[] Pre { get;}
}
When creating Unit objects you actually need to create an array for the "Pre" parameter. Like new Unit("Name", new []{"pre1", "pre2"});
And when outputting the strings you need to access the individual strings in the array, or combine them to a larger string, for example like Console.WriteLine(_u[i].Name + string.Join(" , ", _u[i].Pre));
I am making console app using Array class that has username as object, this is member.cs
Class Member{
public string username;
public Member(){
}
public Member(string username){
username = username;
}
}
And this is my Collection.cs
Class Collection{
static Member[] members = new Member[100];
public void Adduser(){
console.writeLine("username?");
string user_input = console.ReadLine();
members = new Member[]{
new Member(user_input)
};
}
public Member[] get() {
return members;
}
}
but every time the Adduser() functions is called, it only stores one member and keeps updating to a new member, in here I am expecting to have 100 usernames at most.
How should I store multiple values in side the constructor or Array object?
Should I create a new array in member class to store multiple-member?
Even after I implemented index, I get nullexception error in side foreach
public void showMember()
{
var data = record.get();
foreach (var value in data)
{
Console.WriteLine(value.Username);
Console.WriteLine(value.Phonenum);
Console.WriteLine(value.Password);
Console.WriteLine(value.Borrowedmovie);
}
}
that's because you renew the array every time.this might help.
int index=0;
public void Adduser(){
console.writeLine("username?");
string user_input = console.ReadLine();
if(index<members.Length)
{
members[index]=new Member(user_input)
index++;
}
else console.writeLine("overflow");
}
}
also I think it's better if you use list instead of array
static List<Member> members = new List<Member>();
public void Adduser(){
console.writeLine("username?");
string user_input = console.ReadLine();
members.Add(new Member(user_input));
}
Instead of an array you should use an List object.
Class Collection{
static List<Member> members = new List<Member>();
public void Adduser(){
console.writeLine("username?");
string user_input = console.ReadLine();
members.Add(new Member(user_input));
}
}
Use index variable and update it everytime u add an item.
Class Collection{
static Member[] members = new Member[100];
int index = 0;
public void Adduser(){
console.writeLine("username?");
string user_input = console.ReadLine();
members[index] = new Member(user_input);
index++;
}
}
Since array is already instantiated with 100 elements, we can not check length of array to check whether elements exists or not.
Array.length will always give the max length of array since the memory is allocated for 100 elements.
But you can check whether last element exists or not and then you can add the new element.
Below code snippet can help you:
class Member
{
public string _username;
public Member()
{
}
public Member(string username)
{
_username = username;
}
}
class Collection
{
private Member[] members = new Member[100];
private int index = 0;
public void Adduser()
{
Console.WriteLine("username?");
string user_input = Console.ReadLine();
var lastElement = members[members.Length - 1];
if (lastElement != null)
{
Console.WriteLine("members array is already full");
return;
}
members[index] = new Member(user_input);
index++;
}
public void DisplayMembers()
{
foreach (var item in members)
{
if (item != null)
{
Console.WriteLine("UserName {0}", item._username);
}
}
}
}
Following is a code for testing the functionality:
static void Main(string[] args)
{
Collection collection = new Collection();
collection.Adduser();
collection.Adduser();
collection.Adduser();
collection.Adduser();
collection.Adduser();
collection.Adduser();
collection.DisplayMembers();
Console.WriteLine("Start second collection");
Collection collection2 = new Collection();
collection2.Adduser();
collection2.Adduser();
collection2.Adduser();
collection2.Adduser();
collection2.Adduser();
collection2.DisplayMembers();
Console.ReadLine();
}
So I've been hitting my head against the wall trying to fill this list box with ID numbers saved into a text file. It's simple enough to get the lines out of the file and put them into a list box like that, but that ID number is also shared with more information that I want to display in other text boxes.
Edit
So this is a comma delimited file and here is an example of a student's stored information:
1234561, Hubert, Huphrey, 123 Apple, Townsville, Some State, MM/DD/YYYY
To put it plainly, I have this text file that has multiple ID #'s, Names, and Addresses, but I just want to display the ID #'s so they can be clicked on from their list box so the rest of the information can be displayed on screen.
I have already taken in a lot of advice, but my thick head can't figure out a few key points. Let me start off by sharing the code I have so far:
EDIT I have updated the method to work with the new Student Class. But Now I need to figure out how to work with the collection to get the properties of the class.
List<Student> colStudents = new List<Student>();
public MainWindow()
{
InitializeComponent();
}
private void btnGetStudents_Click(object sender, RoutedEventArgs e)
{
try
{
//Define a Student object variable with the name StudentInfo
string strStudentList;
// Declare a StreamReader variable for Student Object
StreamReader srStudent = new StreamReader("StudentData.txt");
// intIndex is the index of the contact chosen
int intIndex = lstStudentsID.SelectedIndex;
//Clear list box to avoid having it fill up too much
lstStudentsID.Items.Clear();
// Read the disk file structure
while (srStudent.EndOfStream == false)
{
// Read disk file into a string variable using the ReadLine method.
strStudentList = srStudent.ReadLine();
// Tokenize the string read from Student object
string[] tokenize = strStudentList.Split(',');
// Create a student object instance from the Student class.
Student StudentInfo = new Student();
// Set properties of Student object to array element containing the student data
StudentInfo.StudentID = int.Parse(tokenize[0]);
StudentInfo.StudentFirstName = tokenize[1];
StudentInfo.StudentLastName = tokenize[2];
StudentInfo.StudentAddressCity = tokenize[3];
StudentInfo.StudnetBirthDate = tokenize[4];
// Add student object to collection
colStudents.Add(StudentInfo);
// Add ID's to the listbox
lstStudentsID.Items.Add(StudentInfo.StudentID);
}
//Close disk file after all records have been read in
srStudent.Close();
}
catch(Exception ex)
{
MessageBox.Show("Experiencing the following disk problems: " + Environment.NewLine + ex.Message, "Disk File", MessageBoxButton.OK, MessageBoxImage.Exclamation);
}
}
EDIT:
Now that I have the while loop working well enough, I need to either figure out how to utilize the collection or just find a way to use a second and third method to print out the selected student's full name and address
Here's my new class:
public class Student
{
// Properties
private double _ID; // Student's ID, double just in case int is too small
private string _StudentFirstName; // Student's Name
private string _StudentLastName;
private string _StudentAddressStreet;
private string _StudentAddressCity;
private string _StudentBirthDate;
// Constructor
public Student()
{
_ID = 0;
_StudentFirstName = "";
_StudentLastName = "";
_StudentAddressStreet = "";
_StudentAddressCity = "";
_StudentBirthDate = "";
}
// ID Property
public double StudentID
{
get { return _ID; }
set { _ID = value; }
}
// First Name Property
public string StudentFirstName
{
get { return _StudentFirstName; }
set { _StudentFirstName = value; }
}
// Last name Property
public string StudentLastName
{
get { return _StudentLastName; }
set { _StudentLastName = value; }
}
// Address Property
public string StudentAddressStreet
{
get { return _StudentAddressStreet; }
set { _StudentAddressStreet = value; }
}
// Address Property
public string StudentAddressCity
{
get { return _StudentAddressCity; }
set { _StudentAddressCity = value; }
}
// Address Property
public string StudnetBirthDate
{
get { return _StudentBirthDate; }
set { _StudentBirthDate = value; }
}
}
You create dictionary with Key as studentid and value as file line
then using dictionary you can populate the list box
when user select particular list item retrieve the data from dictionary do not perform IO operation.
Dictionary studentInfo = new Dictionary();
static void Main(string[] args)
{
StreamReader Student = new StreamReader("StudentData.txt");
// intIndex is the index of the contact chosen
intIndex = lstStudentsID.SelectedIndex;
// Add student to colStudents list
colStudents.Add(Student.ToString());
// Read the disk file structure
while (Student.EndOfStream == false)
{
// Read disk file into a string variable using the ReadLine method.
strStudentInfo = Student.ReadLine();
// Tokenize the string read from Student object
string[] tokenize = strStudentInfo.Split(',');
// Create a student object instance from the Student class.
string temp = tokenize[0];
studentInfo.Add("Key", strStudentInfo);
}
}
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;
public class TestReadFile {
public static void main(String args[]) {
String fileName = "StudentData.txt";
//read file into stream, try-with-resources
try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
stream.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}
}
There are semi answer to this question which I have read through thoroughly, as well as all things MSDN about generic classes but I am still having trouble when a generic class inherits from another class: where T: ClassName
For example, here is my generic list class
public class MyGenericList2<T> where T : Person
{
private T[] list;
public MyGenericList2(int size)
{
list = new T[size];
}
public T getItem(int index)
{
T temp = default(T);
temp = list[index];
return temp;
}
public void setItem(int index, T value)
{
list[index] = value;
}
public void DisplayList()
{
for (int i = 0; i < list.Length; i++)
{
Console.Out.WriteLine(list[i]);
}
}
}
It inherits from the person class:
NOTE: It is shortened for clarity sake
public abstract class Person
{
protected string firstName;
// Getters
public string getFirstName()
{
return this.firstName;
}
public void setFirstName(string fname)
{
this.firstName = fname;
}
}
When I try to call it I get an error about trying to convert a string to a {namespace}.Person which I sort of get, in that I am trying to put a string into a 'Person' box, but how does one call the class using this mechanism?
Here is the main method
public static void Main(string[] args)
{
MyGenericList2<Person> studentGeneric = new MyGenericList2<Person>(3);
Student st1 = new Student();
st1.setFirstName("Thor");
studentGeneric.setItem(0, st1); //This does not work
studentGeneric.setItem(1, Person.setFirstName("Odin"); // Does not work
studentGeneric.setItem(2, st1.setFirstName("Slepnir"); // Does not work
studentGeneric.DisplayList();
Console.ReadLine();
}
If I cut out the Where T : Person and use GenericList2<string> it works fine, which makes sense since it is string to string.
Any help would be appreciated
quick clarification Student inherits from Person:
public class Student : Person
{
// Student 1
private string studentID01 = "001";
public string getStudentID01()
{
return this.studentID01;
}
}
First of all I would recommend using public properties for your classes, for example:
public abstract class Person
{
public string FirstName { get; set; }
}
public class Student : Person
{
public string StudentId { get; set; }
}
This means your list code would work like this:
Student st1 = new Student();
st1.FirstName = "Thor";
studentGeneric.setItem(0, st1);
And you can even use this syntax:
studentGeneric.setItem(1, new Student
{
FirstName = "Odin"
});
Additionally, the .Net Framework already provides a really nice set of generic collection classes you can use so you don't really need your MyGenericList2<T> class. For example, the most commonly used class is System.Collections.Generic.List:
var people = new System.Collections.Generic.List<Person>();
people.Add(new Student
{
FirstName = "Odin"
});
Or even using the collection initialiser syntax:
var people = new System.Collections.Generic.List<Person>
{
new Student
{
FirstName = "Odin"
}
});
Finally, the problem you are having with outputting your values to the console is because C# doesn't know what to do with your class so by default outputs the value of student.ToString(). And becaue you haven't told your class what to do with it, it just outputs the name of the type. You can either override ToString or, much simpler just call the getFirstName() method:
Console.WriteLine(list[i].getFirstName());
You are using setItem incorrectly. This method can be used to set the value of elements in the list array in an instance of MyGenericList2 class.
To use the setFirstName method on an instance of the Student class, first use getItem to return the object instance. For example:
public void Main(string[] args)
{
MyGenericList2<Person> studentGeneric = new MyGenericList2<Person>(3);
Student st1 = new Student();
st1.setFirstName("Thor");
studentGeneric.setItem(0, st1);
Student st2 = new Student();
studentGeneric.setItem(1, st2);
studentGeneric.getItem(1).setFirstName("Odin");
Student st3 = new Student();
studentGeneric.setItem(2, st3);
studentGeneric.getItem(2).setFirstName("Slepnir");
studentGeneric.DisplayList();
Console.ReadLine();
}
To display the list contents correctly, replace your DisplayList() method with:
public void DisplayList()
{
for (int i = 0; i < list.Length; i++)
{
if(list[i] != null){
Console.Out.WriteLine("{0}: {1}", i, list[i].getFirstName());
}
else
{
Console.Out.WriteLine("{0}: [NULL]", i);
}
}
}
I have tried to add 2 types of objects in an Array List and then have tried to display them but somehow it is not working. Do I need to use 2 Array List objects or how is it going to work?
Error Message:
Unable to cast object of type 'ArrayList_Practice.Student' to type
'ArrayList_Practice.Employees'.
class Program
{
static void Main(string[] args)
{
Student st=null;
Employees emp = null;
ArrayList al = new ArrayList();
Console.WriteLine("Enter Records");
for (int i = 0; i < 2; i++)
{
st = new Student();
Console.WriteLine("Enter roll");
st.roll = int.Parse(Console.ReadLine());
Console.WriteLine("Enter name");
st.name = Console.ReadLine();
Console.WriteLine("Enter course");
st.course = Console.ReadLine();
al.Add(st);
emp = new Employees();
Console.WriteLine("Enter empID");
emp.empID = int.Parse(Console.ReadLine());
Console.WriteLine("Enter name");
emp.name = Console.ReadLine();
al.Add(emp);
}
Console.WriteLine("/////////////Show Records//////////");
for (int i = 0; i < 2; i++)
{
Console.WriteLine("Roll "+((Student)al[i]).roll.ToString());
Console.WriteLine("Name "+((Student)al[i]).name);
Console.WriteLine("Course "+((Student)al[i]).course);
Console.WriteLine("EmpID "+((Employees)al[i]).empID.ToString());
Console.WriteLine("EmpName "+((Employees)al[i]).name);
}
Console.ReadKey();
}
}
class Student
{
public int roll{ get; set;};
public string name{ get; set;};
public string course{ get; set;};
}
class Employees
{
public int empID{ get; set;};
public string name{ get; set;};
}
}
Your first element is a Student, and you are trying to cast it to Employee on first iteration in the loop.That's why you are getting an InvalidCastException in run-time.Don't use ArrayLists, use strongly-typed generic collections instead.For ex: List<T>.
If you want to display common properties and you want to store Students and Employees into the same list, you can create a common interface for them and implement it.Then you can have a List<CommonInterface> and store your instances.But if you have different properties (it seems you have) you can't access them using common interface or base class,instead you can simply create an extension method and use Reflection to display all property values like this:
public static class Extensions
{
public static string DisplayPerson<T>(this T source)
{
if(source == null) throw new ArgumentNullException("source");
var flags = BindingFlags.Instance | BindingFlags.Public;
var properties = source.GetType().GetProperties(flags);
if (properties.Any())
{
StringBuilder sb = new StringBuilder();
foreach (var prop in properties)
{
sb.AppendFormat("{0} : {1}", prop.Name, prop.GetValue(source));
sb.AppendLine();
}
return sb.ToString();
}
return string.Empty;
}
}
Then just call it from the loop:
for (int i = 0; i < al.Count; i++)
{
Console.WriteLine(al[i].DisplayPerson());
}
Edit: Another way using common interface
public interface IPerson
{
string Name { get; set; }
int Id { get; set; }
}
class Student : IPerson
{
/* implement the properties */
}
class Employees : IPerson
{
/* implement the properties */
}
static void Main(string[] args)
{
List<IPerson> personList = new List<IPerson>();
personList.Add(new Student {/* set properties */});
personList.Add(new Employee {/* set properties */});
// use a loop and display your properties without casting
}
in your array list, your 0th element is a student type and 1st element is an employee type.
in your loop, then you're trying to cast your 0th element to an employee to display empID.
hence you need to be aware of this..
you need to do proper cast check for the loop to work.
check if the element is student or employee and display accordingly.
for (int i = 0; i < al.Count; i++)
{
var student = al[i] as Student;
if (student != null)
{
Console.WriteLine("Roll "+ student.roll.ToString());
Console.WriteLine("Name "+ student.name);
Console.WriteLine("Course "+ student.course);
}
else
{
var employee = al[i] as Employee;
if (employee != null)
{
Console.WriteLine("EmpID "+ employee.empID.ToString());
Console.WriteLine("EmpName "+ employee.name);
}
}
}
though this works for your problem, in general you should be using strongly types collections.
e.g. List<Student> and List<Employee>
You need two lists, because you are trying to store two different types of objects in the array. While it's possible to manage this, you'd be better off keeping it simple: have an array for students and an array for employees.
I'm not sure why you enter the student and employee records at the same time, in pairs. Are the employees connected to the students in some way? Are the students employees? If so, you'd be better off creating a single object that represents student-employee, or whatever the relationship is, and filling a single list with items of that type.
Also, it's 2014 and you shouldn't be using ArrayList. At the very least, use List<>.