-2

Classes

public class Building
{
    public string Name = "Not To Be Seen";
    ...
}

public class School: Building
{
    public int NoOfRooms = 200;
    public string Address = "123 Main St.";
    ...
}

Goal (n some other class / use case)

// This is a simple example, in reality this code is far more complex
// the class "School" is private from the program
List<Building> city = new List<School>();
// city will only have properties of the class School (or at least those are the only properties seen)

Console.WriteLine(city[0].NoOfRooms.ToString()) // Outputs 200
Console.WriteLine(city[0].Name) // Should not output anything

This seems like it should be very possible depending on correctly converting the lists. However, I cannot seem to figure out how to get this to work. It seems like it involves co-variance, but I do not want an immutable list or type. Doesn't C# offer this kind of conversion easily (i.e. base class can fully mimic a derived class)?

Thanks

G.T.D.
  • 386
  • 1
  • 5
  • 21
  • Your example is wrong, `List Jill` doesn't have properties `ClassRoom` it is a list... – Callum Linington Mar 23 '17 at 14:57
  • How do you expect a `public` field to not be visible to a derived class? – Kenneth K. Mar 23 '17 at 14:58
  • And no, you can't have person behave like teacher, accessing properties that belong only to teacher on a person object will never work..... I would probably rethink your inheritance here... and it is my opinion that you don't use inheritance – Callum Linington Mar 23 '17 at 14:58
  • You will have to make another class that inherits Person if you don't want Teach to see the name property. An inherited class always gets all the properties of the base class. – jdweng Mar 23 '17 at 14:59
  • `Jill` is of type `List`, not `Person`, so it neither has a `ClassRoom` nor a `Name`. Second: Since `Teacher` _inherits_ from `Person` it _does_ have a `Name`. So it's a little unclear what you are asking for. Third: a `List` is _not_ a `List`, so it's not assignable. Even in the `IList` interface `T` is invariant as it's an input as well as an ouput value. – René Vogt Mar 23 '17 at 14:59
  • @CallumLinington oops. I fixed that now. – G.T.D. Mar 23 '17 at 15:00
  • I think the thought "a _base_ class can fully mimic a _derived_ class" shows a total misunderstanding of OOP. It's rather the other way round, if at all. – René Vogt Mar 23 '17 at 15:01
  • `School` *extends* `Building` by deriving from it. Therefore it is a superset of what is offered by `Building`, not a subset. That's just how inheritance works. – Baldrick Mar 23 '17 at 15:04
  • @RenéVogt Not at all. I am just trying to get a very specific implementation of objects and lists. – G.T.D. Mar 23 '17 at 15:06
  • @B1313 - well, you say you understand OO, and you just want a specific implementation... except that the specific implementation you want runs counter to the principles of OO, so I think RenéVogt is making a very reasonable observation. – Mark Adelsberger Mar 23 '17 at 15:23
  • @MarkAdelsberger Well, if we want to be technical, his observation should actually be that I may not be grasping the concept of Inheritance in OOP, but not that I don't understand OOP in the broad scope. The reasoning behind my implementation is that I am trying to hide the derived class from the eyes of the rest of the program and have the Base class act like the objects of the derived class in a list is a natural result of have a list of the base class. To be clearer, I am trying to have the base class spoof the derived class (when needed) without the program knowing anything special is done – G.T.D. Mar 23 '17 at 15:29
  • @B1313 - Using the new example: you can store a `School` in a `List`; you can't assign a `List` to a variable of type `List`. If the rest of the program doesn't know about `School`, then it can't have a list to which only `School`s can be added. To have the variable "act like" its real type though the rest of the program sees it through a base type reference is polymorphism (see `virtual` in C#). And no, if you don't understand inheritance *or polymorphism*, then you don't understand OOP; so quit complaining and start learning form what we're telling you. – Mark Adelsberger Mar 23 '17 at 15:36

2 Answers2

0

Update - Since you completely changed your example, I'll update my answer to reflect the new example. I'm doing this only once; so to anyone reading, if my answer seems out of sync with the question, it's because OP is making unnecessary changes during edits.


There are a few problems here. It is not possible for a List<Base> variable to refer to a List<Derived> instance. This is because, for example, List<Base> must implement operations for adding a Base instance to the List, and a List<Derived> cannot support such an operation.

More generally, the reference type (type as which the variable is declared) defines the interface by which calling code can use the value. So if you need to be able to say city[0].NoOfRooms in your example, then city must be declared as a List<School>. A School could still be stored in a List<Building>, but when you get an item from such a list you would have to try casting to School before using the NoOfRooms property. (And it should be noted that if you find yourself doing this, it suggests a design error.)

The other part of your question has to do with hiding the Name property.

In some languages you could get such an effect through "private inheritance" - but that's not a thing in C#. The closest thing you could do is to have School not by derived from Building, but possibly contain a (private) Building-typed field or property. Then, of course, it wouldn't be possible to store a School in a List<Building> at all.

The other approach would be to have School override the Name property with a getter that returns nothing, which actually is closer to what your code comments suggest.

Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52
0

As per the comments to your question, an object in your List<Building> can not be arbitrarily cast into a School unless it was originally constructed as a School object (or a class derived from School). Consider what would happen if you had another class called Hospital derived from Building and that had its own property say NumberOfPatients and this was one of the objects in that list. You just can't cast a Hospital instance into a School and call the properties available only on School - it just wouldn't make sense to do this.

That said you can still have a List<Building> store any kind of Building objects, including the derived ones (such that you have a mixed list containing Building, School and Hospital objects). Then you could get an enumeration of objects of a specific derived type via Linq OfType (add to the top of your file using System.Linq;). So something like buildingList.OfType<School>() would give you an enumeration of only School objects, which you can now to iterate through and call methods/properties only available on School.

ErrCode
  • 186
  • 2
  • 11