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.
Related
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.
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);
}
}
}
Edit to save you from reading through this whole post
tldr: an object's fields should not be static unless you want all instances of that object to have the same value for that field
I'm trying to create and populate an ArrayList of Blog objects. I do know the generic way do this:
create ArrayList of Blogs
loop (some condition)
create new Blog
add this Blog to AL
However, when I attempt to do so within the while(datareader.read()) loop, all of the elements in the ArrayList are exactly the same Blog. Specifically, I end up with an ArrayList filled with multiple pointers to the very last Blog object from the database table. Here is my code:
public static ArrayList AllBlogs()
{
SqlDataReader dr = anonPage.ExecuteReader("SELECT * FROM Kristina_Blogs");
ArrayList allBlogs = new ArrayList();
if (dr.HasRows)
{
while (dr.Read())
{
Blog b = new Blog();
//grab a row from Kristina_Blogs and assign those attributes to b
b.setTitle(dr["title"].ToString());
b.setMessage(dr["message"].ToString());
b.setId(dr["id"]);
allBlogs.Add(b);
}
}
dr.Close();
return allBlogs;
}
As I said before, the result of this is an ArrayList filled with pointers to the very last blog from the Kristina_Blogs table. I imagine the ArrayList allBlogs looks like [b, b, b, ... b] and therefore they ALL get updated when I say b.setTitle() etc. But how can this be the case if I am creating a NEW Blog object at the beginning of each iteration?
Here is some extra info that you don't have to read but it might clear up some confusion about the structure of the problem:
Blog object has id, title, and message fields and their respective getter/setters
Kristina_Blogs is a table representing these blogs with columns for id, title, message
The suggestions say to include a tag for my DB engine but I can't find a tag for it: Microsoft SQL Server Management Studio
This code works perfectly when I use an ArrayList of Strings instead of Blogs
Edit: Including the code from Blog class
public class Blog
{
public App myApp;
public static string Title;
public static string Message;
public static int Id;
//constructors
public Blog() { }
public Blog(App App) { this.myApp = App; }
//all getters and setters look like this
public string getTitle() { return Title; }
public void setTitle(string t) { Title = t; }
}
The main problem you have, as I mentioned in comments is your member variables are static, so when you set the value, they change in all instances. you should change your code this way:
public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public string Message { get; set; }
}
And fill your list this way, don't forget to add using System.Linq;:
var result = new List<Blog>();
var connection = #"your connection string";
var command = "SELECT * FROM Kristina_Blogs";
var adapter = new System.Data.SqlClient.SqlDataAdapter(command, connection);
var dataTable = new DataTable();
//Get data
adapter.Fill(dataTable);
dataTable.Rows.Cast<DataRow>().ToList()
.ForEach(row =>
{
var b = new Blog();
b.Id = row.Field<int>("Id");
b.Title = row.Field<string>("Title");
b.Message = row.Field<string>("Message");
result.Add(b);
});
return result;
Note:
When you create a member static, it is shared between all instances of that calss.
In C# you can use property to get or set values, you don't need to setX or setY, when you get the value of a property, the get code of that property will execute and when you assign a value to a property the set part of it will execute. you can define properties this way:
Property:
private int id;
public int Id
{
get
{
return id;
}
set
{
id = value;
}
}
or more simple:
public int Id { get; set; }
All of the fields in your Blog class are static, meaning they're shared between all object instances. You want them to be instance field (meaning not static) so that each object has its own copy of each of those values.
Remove the static attributes from your class:
public class Blog
{
public App myApp;
public String Title;
public String Message;
public int Id;
//constructors
public Blog() { }
public Blog(App App) { this.myApp = App; }
//all getters and setters look like this
public String getTitle() { return Title; }
public String getMessage() { return Message; }
public void setTitle(String t) { Title = t; }
public void setMessage(String m) { Message = m; }
}
When you use static variables, all instances of an object will contain the same values in those variables. By removing the static keyword, you are allowing different instances of the object to hold different values.
Now, every time you create a blog object, that object's Title and Message etc, will contain its own information.
I would make a quick method to prevent null value from throwing error
public static string GetSafeString(SqlDataReader reader, int index)
{
if (!reader.IsDBNull(index))
return reader.GetString(index);
else
return string.Empty;
}
Replace this code:
while (dr.Read())
{
Blog b = new Blog();
//grab a row from Kristina_Blogs and assign those attributes to b
b.setTitle(dr["title"].ToString());
b.setMessage(dr["message"].ToString());
b.setId(dr["id"]);
allBlogs.Add(b);
}
With This Code:
while (dr.Read())
{
Blog b = new Blog();
//grab a row from Kristina_Blogs and assign those attributes to b
b.setId(dr.GetInt32(0));
b.setTitle(GetSafeString(dr, 1);
b.setMessage(GetSafeString(dr, 2);
allBlogs.Add(b);
}
Where the number is the index of field in the record and assuming "id" is an integer. Also consider moving creation of "Blog" object outside of loop and just change values.
I'm not sure if I'm just searching the wrong thing or not, I just can't find an example of passing a parent class into a property of that class.
I've attempted to create a simple example which you can see below or view it at https://dotnetfiddle.net/uBGWgp.
I simply would like the Column class to know of its own parent Table, passing through the instance of it via the constructor (new Table()). See comment in code example where I wish to do this: /* Pass parent here? */
using System;
using System.Collections.Generic;
using System.Linq;
public class FakeDb{
public class FakeColumn{
public string ColumnName;
}
public class FakeTable{
public string TableName {get;set;}
public IEnumerable<FakeColumn> Columns {get;set;}
}
public IEnumerable<FakeTable> Tables {get;set;}
public FakeDb(){
Tables = new List<FakeTable>(){
new FakeTable(){
TableName = "People",
Columns = new List<FakeColumn>(){
new FakeColumn(){
ColumnName = "FirstName"
},
new FakeColumn(){
ColumnName = "LastName"
}
}
}
};
}
}
public class Table{
public Guid TableGuid = Guid.NewGuid();
public IEnumerable<Column> Columns;
}
public class Column{
private Table _myTable;
public Guid ColumneGuid = Guid.NewGuid();
public Column(Table hostTable){
_myTable = hostTable;
}
}
public class Program
{
public static void Main()
{
var fakeDb = new FakeDb();
var tableList = fakeDb.Tables.GroupBy(p => p.TableName, p => p, (tableName, values) => new {
TableName = tableName,
OtherValues = values
}).Select(p => new Table(){
Columns = p.OtherValues.Select(i => new Column(/* Pass parent here? */)).ToList()
}).ToList();
}
}
Because you are not holding a reference to the new Table object you are creating, there is no way to do it in a single-lined query. However changing it to a multi-lined lambda expression will make this possible. Save your newly created table in a variable and then pass that variable into your Column's constructor.
You will have to do something like this
.Select(p =>
{
var t = new Table();
t.Columns = p.OtherValues.Select(i => new Column(t)).ToList();
return t;
});
Demo: https://dotnetfiddle.net/1kKxMR
I saw an example on MSDN where it would let you specify the default value if nothing is returned. See below:
List<int> months = new List<int> { };
int firstMonth2 = months.DefaultIfEmpty(1).First();
Is it possible to use this functionality with an object? Example:
class object
{
int id;
string name;
}
code:
List<myObjec> objs = new List<myObjec> {};
string defaultName = objs.DefaultIfEmpty(/*something to define object in here*/).name;
UPDATE:
I was thinking I could do something like this:
List<myObjec> objs = new List<myObjec> {};
string defaultName = objs.DefaultIfEmpty(new myObjec(-1,"test")).name;
But haven't been able to. It should be noted that I am actually trying to use this method on an object defined in my DBML using LINQ-To-SQL. Not sure if that makes a difference in this case or not.
You need to pass an instantiated class as a parameter of the DefaultIfEmpty.
class Program
{
static void Main(string[] args)
{
var lTest = new List<Test>();
var s = lTest.DefaultIfEmpty(new Test() { i = 1, name = "testing" }).First().name;
Console.WriteLine(s);
Console.ReadLine();
}
}
public class Test
{
public int i { get; set; }
public string name { get; set; }
}
To add to it and make it a bit more elegant (IMO) add a default constructor:
class Program
{
static void Main(string[] args)
{
var lTest = new List<Test>();
var s = lTest.DefaultIfEmpty(new Test()).First().name;
Console.WriteLine(s);
Console.ReadLine();
}
}
public class Test
{
public int i { get; set; }
public string name { get; set; }
public Test() { i = 2; name = "testing2"; }
}
As per the MSDN page on this Extension Method you can do what you want:
http://msdn.microsoft.com/en-us/library/bb355419.aspx
Check the sample on this page for an example on how to use this with an object.
i must admit i am not too sure i understand your question, but i'll try to suggest using double question mark if the returned object might be null. Like so:
myList.FirstOrDefault() ?? new myObject();
You can create a default Object Like this:
Object o_Obj_Default = new Object();
o_Obj_Default.id = 3;
o_Obj_Default.name = "C";
And add it to your default value :
string defaultName = objs.DefaultIfEmpty(o_Obj_Default).First().name;
If your list "objs" is empty, the result will be "C"