Using a method to initialize - c#

So up until recently I've been initializing all my stuff within the main function, but this makes it (imo) pretty ugly. So I went ahead and thought instead of having me write out the initializing , I'd just have a method to do it for me which would explain itself just by its name (Create.ClassRoom()). So I went ahead and made this class with the method to do it:
class Create
{
public static void ClassRoom()
{
Student Henry = new Student("Henry", 20);
Student Jeff = new Student("Jeff", 18);
Student Jessica = new Student("Jessica", 22);
Teacher MrLopez = new Teacher("Lopez", "Math", 37);
}
which would make main look much nicer:
class Program
{
static void Main(string[] args)
{
Create.ClassRoom();
Console.WriteLine(Henry.age);
}
}
However, it says Henry doesn't exist in the current context. Now I understand this has to do with scope, but I can't seem to think or find a solution to it. Is my idea just not doable or am I missing something? I'd like it to be so that after I do Create.ClassRoom(); it would allow me to interact with whatever is initialized in there.

Yes, you're right. It has to do with the scope. The initialized variables are not accessible outside of the CreateClassRoom() method. You'll have to return an instance of the class room to the calling method.
Refactor your class as follows:
class ClassRoom
{
public List<Student> Students { get; private set; }
public List<Teacher> Teachers { get; private set; }
public ClassRoom()
{
this.Students = new List<Student>();
this.Teachers = new List<Teacher>();
}
}
class Create
{
public static ClassRoom ClassRoom()
{
ClassRoom classRoom = new ClassRoom();
classRoom.Students.Add(new Student("Henry", 20));
classRoom.Students.Add(new Student("Jeff", 18));
classRoom.Students.Add(new Student("Jessica", 22));
classRoom.Teachers.Add(new Teacher("Lopez", "Math", 37));
return classRoom;
}
}
The Create.ClassRoom() method returns an instance of the ClassRoom object, using which you will be able to access the Students and Teachers in the class.
From Main(), you could access the properties as follows:
static void Main(string[] args)
{
var classRoom = Create.ClassRoom();
Console.WriteLine("Students: ");
foreach (var student in classRoom.Students)
{
Console.WriteLine("Name: {0}; Age: {1}", student.Name, student.Age);
}
Console.WriteLine("Teachers: ");
foreach (var teacher in classRoom.Teachers)
{
Console.WriteLine("Name: {0}; Subject: {1}", teacher.Name, teacher.Subject);
}
}

Henry cannot be accessed by main() because it is within the scope of the function ClassRoom(). You need to make it return a Student object or better yet, create a class that has a getter and setter for the variables you want to access.

Related

Why data in Lazy Loading C# is loaded before I need it?

In one website I read:
Lady loading is the concept of delaying the loading of an object until we need this data. In other words, we load the object on demand, rather than unnecessarily loading data earlier.
I want to try using Lazy Loading in my simple console app.
Student Class
public class Students
{
public string Name { get; set; }
public string Surname { get; set; }
public string PESEL { get; set; }
private Lazy<List<Students>> LazyStudents;
public Students()
{
}
public List<Students> StudentsProperty
{
get
{
if (LazyStudents == null)
LazyStudents = new Lazy<List<Students>>(() => LoadStudensList());
return LazyStudents.Value;
}
}
public List<Students> LoadStudensList()
{
List<Students> tempStudentsList = new List<Students>();
tempStudentsList.Add(new Students() { Name = "Adam", Surname = "Wróbel", PESEL = "96120904999" });
tempStudentsList.Add(new Students() { Name = "Edyta", Surname = "Urbańczyk", PESEL = "76354736458" });
tempStudentsList.Add(new Students() { Name = "Gabriela", Surname = "Rydwańska", PESEL = "72637284923" });
tempStudentsList.Add(new Students() { Name = "Dawid", Surname = "Rytel", PESEL = "62736482732" });
return tempStudentsList;
}
}
Program and Main() method:
class Program
{
static void Main(string[] args)
{
Students students = new Students();
Console.WriteLine("Hello World!");
foreach (var items in students.StudentsProperty)
{
Console.WriteLine($"Imię: {items.Name}");
Console.WriteLine($"Nazwisko: {items.Surname}");
Console.WriteLine($"PESEL: {items.PESEL}");
Console.WriteLine("");
}
Console.WriteLine("Hello World!");
}
}
I suppose that i use Lazy Loading, when i create new object of Students class StudentsProperty (return elements from Lazy List) still empty. Elements to LazyList will be added when i use method using StudentsProperty
foreach (var items in students.StudentsProperty)
{
Console.WriteLine($"Imię: {items.Name}");
Console.WriteLine($"Nazwisko: {items.Surname}");
Console.WriteLine($"PESEL: {items.PESEL}");
Console.WriteLine("");
}
I Add breakpoint before foreach loop and i see that StudentsProperty has elements:
Have I implemented lazy loading incorrectly or do I understand something wrong?
Lazy.Value is when the lazy gets evaluated.
LazyStudents = new Lazy<List<Students>>(() => LoadStudensList());
return LazyStudents.Value;
doesn't make any sense. In the first line you say "evaluate when it's needed" and the second line says "I need it now".
By null checking you've did all the lazy evaluation on your own. Use either this:
private Lazy<List<Students>> LazyStudents = new Lazy<List<Students>>(() => LoadStudensList());
public List<Students> StudentsProperty
{
get
{
return LazyStudents.Value;
}
}
or this:
private List<Students> LazyStudents;
public List<Students> StudentsProperty
{
get
{
if (LazyStudents == null)
LazyStudents = LoadStudensList();
return LazyStudents;
}
}
They're supposed to be conceptually the same thing. Except multithreading safeguards, debugging and probably other pesky details, that make no difference most of the time.
The issue why you see values in debugger is bit more complicated. Looking at the Lazy source, it should display null in debugger, thanks to internal T ValueForDebugDisplay. However, you're NOT looking at value of lazy. By looking at at Students.StudentsProperty you're looking at your get and debbuger evaluates getters and your getter forces Lazy to evaluate. You've bypassed all that debugging code that MS had created for us. Expose the Lazy directly, it's meant to be. Or, instead of debugger, put a log in LoadStudensList()
Bottom line: Lazy is lazy only until Value gets called.

C# list of object and reference the object in the list

I have a question concerning reference of an object in a list.
I have a Students Class as below
private void Form_Load(object sender, EventArgs e)
{
List<Students> ListOfStudents = new List<Students>();
ListOfStudents.Add(new Students("Alex", 1));
ListOfStudents.Add(new Students("Bob", 2));
ListOfStudents.Add(new Students("Cathrine", 3));
ListOfStudents.Add(new Students("Dave", 4));
ListOfStudents.Add(new Students("Eric", 5));
ListOfStudents.Add(new Students("Frank", 6));
foreach (var student in ListOfStudents)
{
Students s = new Students(student.StudentName, student.StudentID);
s.Dosomework();
}
}
public class Students
{
public string StudentName { get; set; }
public int StudentID { get; set; }
public Students()
{ }
public Students(string _studentname, int _studentid)
{
StudentName = _studentname;
StudentID = _studentid;
}
Timer timerDoSomethingEveryTsec = new Timer();
public void Dosomework()
{
InitTimerEveryTsec(5000);
}
public void StopWork()
{
timerDoSomethingEveryTsec.Stop();
}
/// <summary>
/// This is the timer for the action after x time
/// </summary>
public void InitTimerEveryTsec(int t)
{
timerDoSomethingEveryTsec.Tick += new EventHandler(timer1_TickEveryTsec);
timerDoSomethingEveryTsec.Interval = t; // in miliseconds
timerDoSomethingEveryTsec.Start();
}
private void timer1_TickEveryTsec(object sender, EventArgs e)
{
MessageBox.Show(StudentName + " is working with ID " + StudentID);
}
}
And a ListOfStudents.
Now, if when i load my form, the students class will "Dosomework" every tick.
My question is:
How do I access the very specific instantiated "Students s" where s = Eric with the ID = 5.
I want to access the student "ERIC with #5" to s.Stop(). Is there away to achieve that?
thank you.
Well, since none of the instances of Students in your list is actually running the Dosomework method, it's going to be quite hard to stop Eric.
The reason for that is that instead of calling the Dosomework method for the instances in your list, you are creating new instances with the same properties and call the Dosomework method on these instances. This means that by the time your foreach loop ends, s will point to a new instance of the Students class with the name Frank and id 6, and you have no reference to the instance of Eric that is actually doing some work.
So the first thing to change is the code inside the foreach loop - Instead of creating new instances, you should simply execute the Dosomework method on the instances stored in the list:
foreach (var student in ListOfStudents)
{
student.Dosomework();
}
Then you can use the Find method to find the student with id = 5:
var eric = ListOfStudents.Find(s => s.Id == 5);
Now that you've got the correct instance, all you need to do is execute the StopWork method:
eric.StopWork();
Also, I would recommend sticking to c# naming conventions - use Pascal casing for all your methods (so Dosomework becomes DoSomeWork)
var MyStudent = ListOfStudents.Where(x=> x.ID == 5).FirstOrDefault();
Assuming you have...
List<Students> listOfStudents = new List<Students>();
Then you could find a student with...
var eric = listOfStudents.Where(x => x.StudentName=="Eric" && x.StudentID==5).FirstOfDefault(null);
BTW, I'd really recommend calling your class "Student" since each instance represents a single student. This also allows the list variable to be "students" since it represents one or more students.

Generic class where T : Class clarification

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);
}
}
}

Creating multiple inputs to a ClassList

So I have coded for a while I C# and learned the basics, one thing that always stops me is how I can create a class and then use a list for a user to input values.
I don't know if I'm totally off the chart with this code, the problem is that I don't understand why I can't use my newly created object of the class and add input to it. All help is appreciated
class Program
{
static void Main(string[] args)
{
List<Citizen> listOfCitizens = new List<Citizen>();
for (int i = 0; i < listOfCitizens.Count; i++)
{
Console.WriteLine("Enter Surname for the citizen:");
listOfCitizens.SurName.add = Console.ReadLine();
Console.WriteLine("Enter Lastname for the citizen:");
listOfCitizens.Lastname.add = Console.ReadLine();
Console.WriteLine("Enter age of the citizen:");
listOfCitizens.age.add = int.Parse(Console.ReadLine());
}
Console.WriteLine($"Name {Citizen.SurName} {Citizen.LastName} {Citizen.age}");
Console.Read();
}
}
class Citizen
{
public static string SurName{ get; set; }
public static string LastName{get;set;}
public static int age { get; set; }
}
A list of something is not a something. Just like a basket of apples is not an apple. You don't eat the basket, you eat an item from the basket.
So when you create your list:
List<Citizen> listOfCitizens = new List<Citizen>();
You would then create an item to add to the list:
Citizen someCitizen = new Citizen();
someCitizen.SurName = "Smith";
// etc.
And then add it to the list:
listOfCitizens.Add(someCitizen);
Additionally, your Citizen is a little off. Those properties shouldn't be static. Not sure why you made them that way, but you should remove the static keyword from everything in your Citizen class.

Parent and Child Class

I have the following code.
using System;
public class Program
{
public static void Main()
{
Employee FTE = new FullTimeEmployee();
}
}
public class Employee
{
public string FirstName;
public string LastName;
public void PrintFullName()
{
Console.WriteLine(FirstName + " " + LastName);
}
}
public class FullTimeEmployee : Employee
{
public float YearlySalary;
}
I just want to clarify one thing.
If I write Employee FTE = new FullTimeEmployee(); is the object created only able to access the FirstName,LastName,PrintFullName and NOT YearlySalary?
And if I write FullTimeEmployee FTE = new FullTimeEmployee(); is the object created able to access everything INCLUDING YearlySalary?
Thanks
In any case the object is a FullTimeEmployee if you create it via new FullTimeEmployee();. But you have without casting only access to the declaring type. So if you declare it like: FullTimeEmployee FTE = you have full access, if you declare it like Emplyee FTE you have not. But you can simply cast it back.
First solution:
Employee FTE = new FullTimeEmployee();
var employee = (FullTimeEmployee)FTE;
var sal = employee.YearlySalary;
Second solution
Employee FTE = new FullTimeEmployee();
var employee = (FTE as FullTimeEmployee)
var sal = employee.YearlySalary;
This should both work. The difference between this two is, that as will not throw an exception if casting fails, it will just return null.
In your case you could take a look at the var keyword.

Categories

Resources