Reputation: 21
For the sake of explanation I made an example
public class Base {
public string Name { get; set; }
public string Surname { get; set; }
public Base(string name, string surname) {
Name = name;
Surname = surname;
}
}
public class Student : Base {
public int StudentID { get; set; }
public Student(string name, string surname, int studentID)
: base(name, surname) {
Name = name;
Surname = surname;
StudentID = studentID;
}
public override string ToString() {
return string.Format("Name is {0}, surname is {1}, ID is {2}",
Name, Surname, StudentID);
}
}
public class Teacher : Base {
public string TeachingSubject { get; set; }
public Teacher(string name, string surname, string teachingSubject)
: base(name, surname) {
Name = name;
Surname = surname;
TeachingSubject = teachingSubject;
}
public override string ToString() {
return string.Format("Name is {0}, surname is {1}, TeachingSubject is {2}",
Name, Surname, TeachingSubject);
}
}
In my case, there are 4 child classes, but 2 is enough to keep it simple and still hit the point. Keep in mind that Student and Teacher classes contain their own property, so each object from the Base list should be different, according to the derived class properties.
Somewhere in the project I need to have a Method that returns List of Base objects
List<Base> GetAllLists() {
return allLists; //Lets name the return list of Base objects like this
}
So I need to put lists of objects from derived classes to a Base class List and use it somewhere.
I already did something like this
List<Base> GetAllLists() {
var allLists = new List<Base>();
var studentList = new StudentService().GetList(); //Service class that populates the list of students from a csv file
foreach (var item in studentList) {
allLists.Add(new Student(item.Name, item.Surname, item.StudentID));
}
var teacherList = new TeacherService().GetList(); //Service class that populates the list of teachers from a csv file
foreach (var item in teacherList) {
allLists.Add(new Teacher(item.Name, item.Surname, item.TeachingSubject));
}
return allLists;
}
I got a comment:
there's no need to iterate all of the lists and instantiate a new object of each entity, since all of them inherit from the same base class
So how to achieve this in some other way?
Upvotes: 0
Views: 1120
Reputation: 835
You don't need to write Name = name; Surname = surname;
since you already have : base(name, surname)
Regarding to the shadow/deep copy in AddRange()
, you can also implement ICloneable
or add a copy constructor. Example:
Class definations:
public class Base {
public string Name { get; set; }
public string Surname { get; set; }
public Base(string name, string surname) {
Name = name;
Surname = surname;
}
}
public class Student : Base, ICloneable { // ICloneable
public int StudentID { get; set; }
public Student(string name, string surname, int studentID) : base(name, surname) {
//Name = name;
//Surname = surname;
StudentID = studentID;
}
public override string ToString() {
return string.Format("Name is {0}, surname is {1}, ID is {2}", Name, Surname, StudentID);
}
public object Clone() {
return MemberwiseClone();
}
}
public class Teacher : Base { // Copy constructor
public string TeachingSubject { get; set; }
public Teacher(string name, string surname, string teachingSubject) : base(name, surname) {
//Name = name;
//Surname = surname;
TeachingSubject = teachingSubject;
}
public override string ToString() {
return string.Format("Name is {0}, surname is {1}, TeachingSubject is {2}", Name, Surname, TeachingSubject);
}
public Teacher(Teacher obj) : base(obj.Name, obj.Surname) {
TeachingSubject = obj.TeachingSubject;
}
}
Sample usage:
// AddRange()
List<Student> stud = new List<Student>(2);
stud.Add(new Student("s1", "ss1", 1));
stud.Add(new Student("s2", "ss2", 2));
List<Teacher> teac = new List<Teacher>(2);
teac.Add(new Teacher("t1", "ts1", "subject1"));
teac.Add(new Teacher("t2", "ts2", "subject2"));
List<Base> bas = new List<Base>(4);
bas.AddRange(stud);
bas.AddRange(teac);
Debug.Print($"{Environment.NewLine}AddRange():");
Debug.Print($"Base List:{Environment.NewLine}{bas[0]}{Environment.NewLine}{bas[1]}{Environment.NewLine}{bas[2]}{Environment.NewLine}{bas[3]}");
stud[0] = new Student("s3_changed", "ss3_changed", 3);
stud[1].Name = "s4_changed";
stud[1].Surname = "ss4_changed";
stud[1].StudentID = 4;
bas[2].Name = "b3_changed";
bas[2].Surname = "bs3_changed";
((Teacher)bas[2]).TeachingSubject = "bsub3_changed";
bas[3] = new Teacher("t4_changed", "ts4_changed", "tsbu4_changed");
Debug.Print($"{Environment.NewLine}After Change:");
Debug.Print($"Student List:{Environment.NewLine}{stud[0]}{Environment.NewLine}{stud[1]}");
Debug.Print($"Teacher List:{Environment.NewLine}{teac[0]}{Environment.NewLine}{teac[1]}");
Debug.Print($"Base List:{Environment.NewLine}{bas[0]}{Environment.NewLine}{bas[1]}{Environment.NewLine}{bas[2]}{Environment.NewLine}{bas[3]}");
// Concat()
List<Student> stud2 = new List<Student>(2);
stud2.Add(new Student("s1", "ss1", 1));
stud2.Add(new Student("s2", "ss2", 2));
List<Teacher> teac2 = new List<Teacher>(2);
teac2.Add(new Teacher("t1", "ts1", "subject1"));
teac2.Add(new Teacher("t2", "ts2", "subject2"));
List<Base> bas2 = new List<Base>();
bas2 = bas2.Concat(stud2).Concat(teac2).ToList();
Debug.Print($"{Environment.NewLine}Concat:");
Debug.Print($"Base List:{Environment.NewLine}{bas2[0]}{Environment.NewLine}{bas2[1]}{Environment.NewLine}{bas2[2]}{Environment.NewLine}{bas2[3]}");
stud2[0] = new Student("s3_changed", "ss3_changed", 3);
stud2[1].Name = "s4_changed";
stud2[1].Surname = "ss4_changed";
stud2[1].StudentID = 4;
bas2[2].Name = "b3_changed";
bas2[2].Surname = "bs3_changed";
((Teacher)bas2[2]).TeachingSubject = "bsub3_changed";
bas2[3] = new Teacher("t4_changed", "ts4_changed", "tsbu4_changed");
Debug.Print($"{Environment.NewLine}After Change:");
Debug.Print($"Student List:{Environment.NewLine}{stud2[0]}{Environment.NewLine}{stud2[1]}");
Debug.Print($"Teacher List:{Environment.NewLine}{teac2[0]}{Environment.NewLine}{teac2[1]}");
Debug.Print($"Base List:{Environment.NewLine}{bas2[0]}{Environment.NewLine}{bas2[1]}{Environment.NewLine}{bas2[2]}{Environment.NewLine}{bas2[3]}");
// AddRange() clone
List<Student> stud3 = new List<Student>(2);
stud3.Add(new Student("s1", "ss1", 1));
stud3.Add(new Student("s2", "ss2", 2));
List<Teacher> teac3 = new List<Teacher>(2);
teac3.Add(new Teacher("t1", "ts1", "subject1"));
teac3.Add(new Teacher("t2", "ts2", "subject2"));
List<Base> bas3 = new List<Base>(4);
bas3.AddRange(stud3.Select(x => (Student)x.Clone()).ToList()); // Clone
bas3.AddRange(teac3.Select(x => new Teacher(x)).ToList()); // Copy c'tor
Debug.Print($"{Environment.NewLine}AddRange() clone:");
Debug.Print($"Base List:{Environment.NewLine}{bas3[0]}{Environment.NewLine}{bas3[1]}{Environment.NewLine}{bas3[2]}{Environment.NewLine}{bas3[3]}");
stud3[0] = new Student("s3_changed", "ss3_changed", 3);
stud3[1].Name = "s4_changed";
stud3[1].Surname = "ss4_changed";
stud3[1].StudentID = 4;
bas3[2].Name = "b3_changed";
bas3[2].Surname = "bs3_changed";
((Teacher)bas3[2]).TeachingSubject = "bsub3_changed";
bas3[3] = new Teacher("t4_changed", "ts4_changed", "tsbu4_changed");
Debug.Print($"{Environment.NewLine}After Change:");
Debug.Print($"Student List:{Environment.NewLine}{stud3[0]}{Environment.NewLine}{stud3[1]}");
Debug.Print($"Teacher List:{Environment.NewLine}{teac3[0]}{Environment.NewLine}{teac3[1]}");
Debug.Print($"Base List:{Environment.NewLine}{bas3[0]}{Environment.NewLine}{bas3[1]}{Environment.NewLine}{bas3[2]}{Environment.NewLine}{bas3[3]}");
Output:
AddRange():
Base List:
Name is s1, surname is ss1, ID is 1
Name is s2, surname is ss2, ID is 2
Name is t1, surname is ts1, TeachingSubject is subject1
Name is t2, surname is ts2, TeachingSubject is subject2
After Change:
Student List:
Name is s3_changed, surname is ss3_changed, ID is 3
Name is s4_changed, surname is ss4_changed, ID is 4
Teacher List:
Name is b3_changed, surname is bs3_changed, TeachingSubject is bsub3_changed
Name is t2, surname is ts2, TeachingSubject is subject2
Base List:
Name is s1, surname is ss1, ID is 1
Name is s4_changed, surname is ss4_changed, ID is 4
Name is b3_changed, surname is bs3_changed, TeachingSubject is bsub3_changed
Name is t4_changed, surname is ts4_changed, TeachingSubject is tsbu4_changed
Concat:
Base List:
Name is s1, surname is ss1, ID is 1
Name is s2, surname is ss2, ID is 2
Name is t1, surname is ts1, TeachingSubject is subject1
Name is t2, surname is ts2, TeachingSubject is subject2
After Change:
Student List:
Name is s3_changed, surname is ss3_changed, ID is 3
Name is s4_changed, surname is ss4_changed, ID is 4
Teacher List:
Name is b3_changed, surname is bs3_changed, TeachingSubject is bsub3_changed
Name is t2, surname is ts2, TeachingSubject is subject2
Base List:
Name is s1, surname is ss1, ID is 1
Name is s4_changed, surname is ss4_changed, ID is 4
Name is b3_changed, surname is bs3_changed, TeachingSubject is bsub3_changed
Name is t4_changed, surname is ts4_changed, TeachingSubject is tsbu4_changed
AddRange() clone:
Base List:
Name is s1, surname is ss1, ID is 1
Name is s2, surname is ss2, ID is 2
Name is t1, surname is ts1, TeachingSubject is subject1
Name is t2, surname is ts2, TeachingSubject is subject2
After Change:
Student List:
Name is s3_changed, surname is ss3_changed, ID is 3
Name is s4_changed, surname is ss4_changed, ID is 4
Teacher List:
Name is t1, surname is ts1, TeachingSubject is subject1
Name is t2, surname is ts2, TeachingSubject is subject2
Base List:
Name is s1, surname is ss1, ID is 1
Name is s2, surname is ss2, ID is 2
Name is b3_changed, surname is bs3_changed, TeachingSubject is bsub3_changed
Name is t4_changed, surname is ts4_changed, TeachingSubject is tsbu4_changed
Upvotes: 0
Reputation: 23732
I guess the AddRange method will allow you to add all objects in one blow:
var allLists = new List<Base>();
var studentList = new StudentService().GetList();
allLists.AddRange(studentList);
var teacherList = new TeacherService().GetList();
allLists.AddRange(teacherList);
Since Student
and Teacher
inherit from base they just can fit into the base List.
The big difference here is that you add only references! that means if you change a value in the original studentList
it will also be changed in the allLists
list!
Whereas in your posted code this will not happen, because you create a new instance for each entry in your studentList
. This way you create independence between the two lists.
But if studentList
is only a local variable that is not manipulated elsewhere it is legitimate to use AddRange
and add simply the references to the allLists
list
Here is a small test program. Copy paste it into a console application and see the difference for yourself. Just change the copyreference
value and compare the outcome:
void Main()
{
bool copyreference = true;
var allLists = new List<Base>();
var studentList = new List<Student>();
studentList.Add(new Student("Alf", "Bedrock", 123));
studentList.Add(new Student("Alfine", "Bedrock", 456));
var teacherList = new List<Teacher>();
teacherList.Add(new Teacher("Brad", "Gulp", "MATH"));
teacherList.Add(new Teacher("Evelyn", "Gulp", "BIO"));
if (copyreference)
{
allLists.AddRange(studentList);
allLists.AddRange(teacherList);
}
else
{
foreach (var item in studentList)
{
allLists.Add(new Student(item.Name, item.Surname, item.StudentID));
}
}
Console.WriteLine(String.Join(Environment.NewLine, allLists));
// TEST changing a value in the original list
studentList[0].Name = "Harry";
// if you copied references you will see the change in the final list
Console.WriteLine(Environment.NewLine + String.Join(Environment.NewLine, allLists));
}
Upvotes: 1
Reputation: 22945
I would do the following, if it is allowed to create a new instance of a list when the GetAllLists
method is called
public List<Base> GetAllLists() {
var studentList = new StudentService().GetList();
var teacherList = new TeacherService().GetList();
return studentList.Cast<Base>()
.Concat(teacherList.Cast<Base>())
.ToList();
}
Upvotes: 0