4

I keep seeing List derived classes that look something like this

class MyClassList : List<MyClass> { public MyClass this[int index] { get { return (MyClass)base[index]; } } } 

What is the point of this inheritance? It looks like it just restates the casting of the member. I could understand other types of indexer, but this is just a restatement of the default List indexer, and provokes a Visual Studio warning RE: hiding of the base indexer. Is this the right or wrong thing to do, and why?

4
  • 3
    I dont know where you see such code, but there are millions of things just plain wrong with it! Commented Mar 19, 2012 at 15:28
  • 2
    where do you keep seeing that? Because I've never seen it. It is a horrible piece of code. Commented Mar 19, 2012 at 15:29
  • 4
    A guess: Newb coder tried to hide the setter. (lol) Commented Mar 19, 2012 at 15:29
  • 1
    @flq Alas, it would have been among the zillion tutorials, code samples, how-to-do-blah-blah's that I've pulled up in the last few weeks as I've ramped up my C#. Rest assured, if I find another one, I'll post the link, so that the full fury of SO may be unleashed upon the hapless perpetrator. Commented Mar 19, 2012 at 15:50

7 Answers 7

5

Perhaps it's a very poor attempt to prevent the overwriting of values via the indexer?

MyClassList x = new MyClassList(); x.Add(new MyClass()); x[0] = new MyClass(); // Error! 

Of course, it doesn't stop this:

List<MyClass> x = new MyClassList(); x.Add(new MyClass()); x[0] = new MyClass(); // No problem here... 

Basically, it's a bad idea. Poor code abounds, unfortunately - don't infer usefulness from mere existence :(

Sign up to request clarification or add additional context in comments.

Comments

2

There is no good reason for this. It hides the base indexer instead of overriding it, which could be dangerous, and it doesn't have any effect at all.

In most cases, it's best just to use a List<MyClass> directly. There's no need to create a special class for this if you're not planning to extend List<>'s functionality at all.

2 Comments

Ok, follow-up to that--if one is extending the base, I assume that base indexer should be left alone, correct?
@downwitch: Yes, unless there is a specific reason to do so. It is possible, for example, that you want to fire an event any time the collection is changed. In that case you would override (not hide) the base indexer, causing it to invoke the base indexer and then fire the appropriate event. Or you might decide that after a certain flag is set, no changes are allowed: in this case you would override the base indexer to throw an exception if that flag is set. There are legitimate reasons to override the indexer. There are far fewer reasons to hide it. And in this case, neither applies.
1

I don't see any usefulness to doing this. Also, the cast is unnecessary.

Comments

1

I think it is supposed to hide the set accessor of the base class, to make it look like the indexer is read-only. But it's useless, because it's very easy to work around:

MyClassList list = ... ((List<MyClass>)list)[index] = value; 

Anyway, the List<T> class isn't designed for inheritance. If you need to create a specialized collection, inherit from Collection<T> instead.

3 Comments

I find your last statement a little confusing. Isn't polymorphism based on the idea that any class is designed for inheritance? It seems to me that the number of out-of-the-box methods and the relative ease of reuse of List<T> make it a faster base class to build from. What am I missing?
What you're missing is that none of the methods in the List<T> class are virtual, which makes it impossible to override them. You can always hide them, but it's a completely different concept... methods that hide the base class definition won't participate in polymorphism.
Indeed, that makes very good sense, and as much as I've read on the subject I can remember no one bothering to state that simple dictum: If a class is designed for inheritance, its methods are virtual. Perhaps obvious, but not to me.
0

I've seen this type of stuff before where people want to serialise it out as another type, for now if thats the only code in there and its not required to be of type MyClassList for other reasons, its totally pointless.

Comments

0

this is, basically, a try to make correctly override of [] access to List, to implement some custom element access logic.

Worth mantioned that the code provided is not good, if not just dangerous. If you want to do somethign tricky with list do not override (or tend to do so) [], but implement some custom method for that purpose.

Comments

0

My guess would be that the code was trying to behave as a read-only List. One would be unable to write to an item of a variable of type MyClassList<T> by index, though one would be able to cast it back to List<T> and write a variable that way. There are times when it makes sense to have a variable whose type has limited abilities, hold an object whose actual capabilities are much greater. The proper way to do that, though, is generally with interfaces, a prime example being IEnumerable<T>. If List<T> is passed to a routine which accepts a parameter of type IEnumerable<T>, the routine could cast its parameter back to a List<T> and use members like Add(), Remove(), etc. but must routines which accept a parameter of type IEnumerable<T> won't try to use it as anything else.

A major problem with the style of code shown by the original poster is that the more 'powerful' direction is the base, rather than the derived type. Because List<T> derives from IEnumerable<T>, that means that all instances of List<T> can be enumerated, but not only some enumerable things have the extra capabilities in List<T>. By contrast, as your class is implemented, every MyClassList<T> can be read and written, but only some instances of List<T> can be used as a MyClassList<T>.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.