I am not strong in OOP. Help me design the classes correctly.

SchoolReport.cs

public class SchoolReport { public string SchoolName { get; set; } public string AreaName { get; set; } public List<LearnerReport> LearnerReports { get; set; } } 

LearnerReport.cs

 public class LearnerReport //Лист оценки обучающегося { //данные обучающегося public string SNS { get; set; } //ФИО участника public string ClassName { get; set; } } 

LearnerReport_201636.cs

 //2016-36 - Готовность 1 классов 2016/2017 public class LearnerReport_201636 : LearnerReport { public double? PrimaryMark { get; set; } public string OldGroupName { get; set; } //Возрастная группа: 6-7 лет/7-8 лет public string WasOrWasntDOO_str { get; set; } //ДА/НЕТ public string WasOrWasnt_str { get; set; } //ДА/НЕТ public string TestResult5Name { get; set; } //Какая группа на основе тестового балла public string ValueArray { get; set; } //Баллы за задания = 1;1;0;0;1... } 

SchoolReport_201636.cs

 public class SchoolReport_201636 : SchoolReport { } 

As you can see in the SchoolReport there is a композиция . How do I now correctly in the specific implementation of SchoolReport_201636 point to a specific implementation of LearnerReports_201636 ?

I try to do it like this:

Program.cs

 SchoolReport schoolReport = new SchoolReport_201636(); schoolReport.LearnerReports = new List<LearnerReport_201636>(); //ТУТ ОШИБКА 

but on the second line of the code, the medium shows:

enter image description here

What am I doing wrong?

  • What actions are planned with the field: public List<LearnerReport> LearnerReports ? - Grundy
  • @Grundy there will add LearnerReport objects that will be formed from DB rows. - Adam
  • Any LearnerReport or only LearnerReport_201636 ? - Grundy
  • @Grundy any. If I correctly understood the principles of SOLID , then probably any. - Adam
  • That is, LearnerReport from other schools can be added to LearnerReport ? - Grundy

2 answers 2

You can use generalizations:

 public class SchoolReport<T> where T : LearnerReport { public string SchoolName { get; set; } public string AreaName { get; set; } public List<T> LearnerReports { get; set; } } public class SchoolReport_201636 : SchoolReport<LearnerReport_201636> { } 

Now compiles:

 var schoolReport = new SchoolReport_201636(); schoolReport.LearnerReports = new List<LearnerReport_201636>(); 

You can also use the covariance and declare the LearnerReports list as an IEnumerable<LearnerReport> (thanks to @Grundy for the tip). But the application of this method depends on your requirements:

 public class SchoolReport { public string SchoolName { get; set; } public string AreaName { get; set; } public IEnumerable<LearnerReport> LearnerReports { get; set; } } 
  • Is an example of the author is a composition ? sort of the same inheritance - Bald
  • @Bald why are you asking me this? :) But I will try to answer: the composition here is the school-student relationship. It was with her (along with inheritance) that the author had problems. - andreycha
  • one
    and if IEnumerable <LearnerReport> is replaced with List <LearnerReport>, will it be assigned? - Grundy
  • I ask you because I myself am not completely sure, and your answer does not clarify that this is not a composition but an inheritance. so I check with you - Bald
  • one
    @Grundy yes, depends on usage scenarios. But to complete the picture fit. - andreycha

If you will use the list of items of type base class

 SchoolReport schoolReport = new SchoolReport_201636(); schoolReport.LearnerReports = new List<LearnerReport>(); 

, then you can use it to add the objects of the inheriting class

 var lr_201636 = new LearnerReport_201636 { PrimaryMark = 4.0, OldGroupName = "7-8 лет ", WasOrWasntDOO_str = "ДА", WasOrWasnt_str = "ДА", TestResult5Name ="Хорошист" }; schoolReport.LearnerReports.Add(lr_201636); 

But when taking an element from the list, it will have to be cast to type if you need to explicitly use the properties of the heir.

 double mark = (LearnerReport_201636)schoolReport.LearnerReports[0]; 

And this is bad, because if the list contains an instance of another class, an exception will be thrown. But if the list elements do not require the use of methods and properties of the inheriting classes, for example, you defined some method in the ancestor, and in the successor it overloaded

 public class LearnerReport //Лист оценки обучающегося { //данные обучающегося public string SNS { get; set; } //ФИО участника public string ClassName { get; set; } public virtual string GetFullInfo() { return string.Format ("ФИО:{0}; Класс{1}", SNS, ClassName); } } //2016-36 - Готовность 1 классов 2016/2017 public class LearnerReport_201636 : LearnerReport { public double? PrimaryMark { get; set; } public string OldGroupName { get; set; } //Возрастная группа: 6-7 лет/7-8 лет public string WasOrWasntDOO_str { get; set; } //ДА/НЕТ public string WasOrWasnt_str { get; set; } //ДА/НЕТ public string TestResult5Name { get; set; } //Какая группа на основе тестового балла public string ValueArray { get; set; } //Баллы за задания = 1;1;0;0;1... public override string GetFullInfo() { return base.GetFullInfo + string.Format ("; Оценка:{0}; Возраст {1}", PrimaryMark, OldGroupName); } } 

then you can do something like that

 foreach(var lr in schoolReport.LearnerReports) { Console.WriteLine(lr.GetFullInfo()); }