Thursday 16 November 2017

c# - Why not inherit from List?

itemprop="text">


When planning out my
programs, I often start with a chain of thought like
so:




A football
team is just a list of football players. Therefore, I should represent it
with:



var football_team = new
List();



The ordering of this list represent the order in which the players are listed
in the
roster.





But
I realize later that teams also have other properties, besides the mere list of players,
that must be recorded. For example, the running total of scores this season, the current
budget, the uniform colors, a string representing the name of
the team, etc..



So then I
think:




Okay, a
football team is just like a list of players, but additionally, it has a name (a
string) and a running total of scores (an
int). .NET does not provide a class for storing football teams,
so I will make my own class. The most similar and relevant existing structure is
List, so I will inherit from
it:



class FootballTeam :
List

{
public string TeamName;

public int RunningTotal

}



But
it turns out that a
guideline says you shouldn't inherit from
List
. I'm thoroughly confused by this
guideline in two respects.



Why
not?




Apparently href="https://stackoverflow.com/a/5376358/1042555">List is
somehow optimized for performance. How so? What performance problems will I
cause if I extend List? What exactly will
break?



Another reason I've seen is that
List is provided by Microsoft, and I have no control over it,
so href="https://stackoverflow.com/questions/5376203/inherit-listt#comment6077237_5376343">I
cannot change it later, after exposing a "public API". But I struggle to
understand this. What is a public API and why should I care? If my current project does
not and is not likely to ever have this public API, can I safely ignore this guideline?
If I do inherit from List and it turns out
I need a public API, what difficulties will I
have?



Why does it even matter? A list is a list.
What could possibly change? What could I possibly want to
change?



And lastly, if Microsoft did not want me
to inherit from List, why didn't they make the class
sealed?



What else am I
supposed to use?




Apparently, for
custom collections, Microsoft has provided a Collection class
which should be extended instead of List. But this class is
very bare, and does not have many useful things, href="https://stackoverflow.com/questions/1474863/addrange-to-a-collection">such as
AddRange, for instance. href="https://stackoverflow.com/a/12039943/1042555">jvitor83's answer
provides a performance rationale for that particular method, but how is a slow
AddRange not better than no
AddRange?



Inheriting
from Collection is way more work than inheriting from
List, and I see no benefit. Surely Microsoft wouldn't tell me
to do extra work for no reason, so I can't help feeling like I am somehow
misunderstanding something, and inheriting Collection is
actually not the right solution for my
problem.



I've seen suggestions such as
implementing IList. Just no. This is dozens of lines of
boilerplate code which gains me nothing.



Lastly,
some suggest wrapping the List in something:



class FootballTeam


{
public List Players;

}


There are
two problems with
this:




  1. It makes my
    code needlessly verbose. I must now call my_team.Players.Count
    instead of just my_team.Count. Thankfully, with C# I can define
    indexers to make indexing transparent, and forward all the methods of the internal
    List... But that's a lot of code! What do I get for all that
    work?


  2. It just plain doesn't make any
    sense. A football team doesn't "have" a list of players. It is the
    list of players. You don't say "John McFootballer has joined SomeTeam's players". You
    say "John has joined SomeTeam". You don't add a letter to "a string's characters", you
    add a letter to a string. You don't add a book to a library's books, you add a book to a
    library.





I
realize that what happens "under the hood" can be said to be "adding X to Y's internal
list", but this seems like a very counter-intuitive way of thinking about the
world.



My question
(summarized)



What is the correct C# way of
representing a data structure, which, "logically" (that is to say, "to the human mind")
is just a list of things with a few
bells and whistles?



Is inheriting from
List always unacceptable? When is it acceptable?
Why/why not? What must a programmer consider, when deciding whether to inherit from
List or not?


class="post-text" itemprop="text">
class="normal">Answer





There are some good answers here.
I would add to them the following
points.




What is
the correct C# way of representing a data structure, which, "logically" (that is to say,
"to the human mind") is just a list of things with a few bells and
whistles?




Ask any
ten non-computer-programmer people who are familiar with the existence of football to
fill in the blank:



A football team
is a particular kind of
_____



Did
anyone say "list of football players with a few bells and
whistles", or did they all say "sports team" or "club" or "organization"? Your notion
that a football team is a particular kind of list of players is in
your human mind and your human mind alone.



List is a
mechanism. Football team is a business object
-- that is, an object that represents some concept that is in the business
domain
of the program. Don't mix those! A football team is a kind
of
team; it has a roster, a roster is a list
of players
. A roster is not a particular kind of list of
players
. A roster is a list of players. So make a
property called Roster that is a
List. And make it
ReadOnlyList while you're at it, unless you
believe that everyone who knows about a football team gets to delete players from the
roster.




Is
inheriting from List always unacceptable?




Unacceptable to
who? Me? No.






When is it acceptable?




When you're
building a mechanism that extends the List
mechanism
.





What must a programmer consider, when deciding whether to inherit from
List or
not?





Am
I building a mechanism or a business object?




But that's a lot
of code! What do I get for all that
work?




You spent
more time typing up your question that it would have taken you to write forwarding
methods for the relevant members of List fifty times
over. You're clearly not afraid of verbosity, and we are talking about a very small
amount of code here; this is a few minutes
work.



UPDATE




I
gave it some more thought and there is another reason to not model a football team as a
list of players. In fact it might be a bad idea to model a football team as
having a list of players too. The problem with a team as/having a
list of players is that what you've got is a snapshot of the team
at a moment in time. I don't know what your business case is for
this class, but if I had a class that represented a football team I would want to ask it
questions like "how many Seahawks players missed games due to injury between 2003 and
2013?" or "What Denver player who previously played for another team had the largest
year-over-year increase in yards ran?" or " href="http://theoatmeal.com/comics/working_home">Did the Piggers go all the way this
year?"



That is, a football team seems
to me to be well modeled as a collection of historical facts such
as when a player was recruited, injured, retired, etc. Obviously the current player
roster is an important fact that should probably be front-and-center, but there may be
other interesting things you want to do with this object that require a more historical
perspective.


No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...