Overload List<>.Add method

  • Thread starter Finn Stampe Mikkelsen
  • Start date
F

Finn Stampe Mikkelsen

Hi

Working with a custom class i'm going to use with a List<>. Using the add
method i need to supply a class-object, but i would like to overload the
method, so that i could supply the add with the individual
properties(fields) of the costum class which it then in turn puts into the
List<< appropriately.

Been trying various searches, but can't seem to find any answers to my
problem. Anyone here ??

/Finn
--
Der er 10 slags mennesker - Dem som forstår binær og dem som ikke gør.
There are 10 kinds of people. Those who understand binary and those who
don't.
Es gibt 10 Arten von Menschen. Die, die Binär verstehen, bzw. die, die es
nicht tuhen.
 
P

Peter Duniho

Hi

Working with a custom class i'm going to use with a List<>. Using the
add method i need to supply a class-object, but i would like to overload
the method, so that i could supply the add with the individual
properties(fields) of the costum class which it then in turn puts into
the List<< appropriately.

Been trying various searches, but can't seem to find any answers to my
problem. Anyone here ??

You can't overload a method unless you are implementing/sub-classing the
type with the original method.

I'm not a big fan of inheriting collection classes (or most framework
classes, for that matter...a few are specifically intended to be
inherited, the rest should probably not be in most cases). One
alternative to inheriting/overloading is to provide an extension method
with the arguments you want.

For example:

static class Extensions
{
public static void Add(this List<MyClass> list, string strName,
int id)
{
list.Add(new MyClass(strName, id));
}
}

(I'm assuming here that you can write an extension method for a
fully-qualified generic type; I'm not sure why one wouldn't be able to,
but I'm not able to test it at the moment, and I've been wrong about
corner cases like that before :) ).

Pete
 
F

Finn Stampe Mikkelsen

Peter Duniho said:
You can't overload a method unless you are implementing/sub-classing the
type with the original method.

I'm not a big fan of inheriting collection classes (or most framework
classes, for that matter...a few are specifically intended to be
inherited, the rest should probably not be in most cases). One
alternative to inheriting/overloading is to provide an extension method
with the arguments you want.

For example:

static class Extensions
{
public static void Add(this List<MyClass> list, string strName,
int id)
{
list.Add(new MyClass(strName, id));
}
}

(I'm assuming here that you can write an extension method for a
fully-qualified generic type; I'm not sure why one wouldn't be able to,
but I'm not able to test it at the moment, and I've been wrong about
corner cases like that before :) ).

Pete

Hi Pete...

Never had experience with entension classes, but i'v tried your suggestion
and with some additional tweeks it works.. No wonder i did not find anything
trying to fin it using overlay.. ;_)

i'm compiling to framework 2.0 as target, so i needed to do a workaround to
accomodate the System.Runtime.CompilerServices;

I put this into my code :

//override the .net 3.5 compiler services for .net 2.0 compatibility
//see: http://kohari.org/2008/04/04/extension-methods-in-net-20/
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false,
Inherited = false)]
public class ExtensionAttribute : Attribute
{

}
}

and it worked like a charm...

Tnx a lot... ;-)

/Finn
 
K

kndg

Hi Finn,

I'm just wondering why do you go the hard way when there is a straight
way to do it? Although the extension method have some usefulness but it
should be used with care. In C# 3.0, extension method is just a
syntactic sugar to a static class.

internal static class MyCollection
{
public static void Add(List<MyClass> list, string strName, int id)
{
list.Add(new MyClass(strName, id));
}
}

then just call the static class method to add the item to the list.

MyCollection.Add(myList, "test", 123);

Or, you could just inherit the List<T> class to make it a specialize
collection class (which you intended to do... by overriding the original
Add method)

public class MyCollection : List<MyClass>
{
public void Add(string name, int id)
{
Add(new MyClass(strName, id));
}
}

then create your list as below,

MyCollection list = new MyCollection();
list.Add("test", 123);

Regards.

Finn Stampe Mikkelsen wrote:
[...]
 
P

Peter Duniho

Hi Finn,

I'm just wondering why do you go the hard way when there is a straight
way to do it? Although the extension method have some usefulness but it
should be used with care. In C# 3.0, extension method is just a
syntactic sugar to a static class.

internal static class MyCollection
{
public static void Add(List<MyClass> list, string strName, int id)
{
list.Add(new MyClass(strName, id));
}
}

then just call the static class method to add the item to the list.

The reason for not doing a plain static method is exactly because the
"syntactic sugar" is nicer. That's why we call it "sugar".
MyCollection.Add(myList, "test", 123);

Or, you could just inherit the List<T> class to make it a specialize
collection class (which you intended to do... by overriding the original
Add method)

The reason for not doing it via inheritance is, as I pointed out earlier,
actually overloading a method in an existing collection class should
generally be avoided, mainly because inheriting an existing collection
class should be avoided. Using an extension/static method instead allows
the type to remain exactly the List<T> class that would be expected
elsewhere. In most contexts, one can replace a List<T> with a class that
inherits List<T>, but there are some corner-case exceptions and there's no
real advantage to exposing oneself to those cases anyway.

Pete
 
K

kndg

Peter Duniho wrote:
[...]
The reason for not doing it via inheritance is, as I pointed out
earlier, actually overloading a method in an existing collection class
should generally be avoided, mainly because inheriting an existing
collection class should be avoided.

Do you mind to give some particular cases on why inheriting a collection
class should be avoided? I had no problem in the past but well I'm
willing to learn. I think by limiting oneself like this will only
limiting the full potential of the .Net framework itself. If it is
really that bad then I think the framework author would have sealed the
class long before...

Unless I have a good reason, then I would...

Just do it! :)

Regards.
 
P

Peter Duniho

Peter Duniho wrote:
[...]
The reason for not doing it via inheritance is, as I pointed out
earlier, actually overloading a method in an existing collection class
should generally be avoided, mainly because inheriting an existing
collection class should be avoided.

Do you mind to give some particular cases on why inheriting a collection
class should be avoided?

Inheriting _any_ class should be avoided. The word "avoid" doesn't mean
you should never do it. It just means that you should prefer to solve
your problem in another way.

Inheritance creates a very close relationship between your new class and
the base class. It also _creates a whole new class_! Generics are
complicated enough, where you get a whole new class just by using a
different type parameter. So to create yet another whole new class just
to add a single method just compounds that issue.

It's my opinion that these general rules of thumb apply with extra
strength to the built-in classes, at least those not specifically designed
for inheritance in mind (e.g. abstract classes like Stream,
CollectionBase, etc.), because the benefits tend not outweigh the added
complexity. It's not a hard-and-fast rule -- one thing inheritance allows
you to do is store additional data with the instance, and that's a lot
more complicated to do without inheritance -- but it should be the guiding
principle, going against it only when one has considered carefully the
reasons and alternatives and has decided that inheritance is clearly the
best solution.

Another issue is that sometimes people try to inherit a collection class
to hide members of the base class. That doesn't seem to be the case here,
but it's another example of where inheriting the class is a bad idea.
Member hiding is almost never the right approach, since in spite of the
use of the word "hide", it's not a security feature at all (i.e. you can
hide a member, but the hidden member is always still accessible to code
that wants it or, worse, to code that doesn't realize there's a derived
class hiding the member).

Basically, the general OOP rule is that if there's a simple way to avoid
inheriting a class, then do that instead of inheriting a class.
Inheritance should be used where it makes the code _better_ in some
observable way. That is not the case here.
I had no problem in the past but well I'm willing to learn. I think by
limiting oneself like this will only limiting the full potential of the
.Net framework itself. If it is really that bad then I think the
framework author would have sealed the class long before...

Just because a class isn't sealed, that doesn't mean that inheriting the
class is always the right way to a solution.

Pete
 
K

kndg

Peter said:
Peter Duniho wrote:
[...]
The reason for not doing it via inheritance is, as I pointed out
earlier, actually overloading a method in an existing collection
class should generally be avoided, mainly because inheriting an
existing collection class should be avoided.

Do you mind to give some particular cases on why inheriting a
collection class should be avoided?

Inheriting _any_ class should be avoided. The word "avoid" doesn't mean
you should never do it. It just means that you should prefer to solve
your problem in another way.

But, solving through extension methods is also in my opinion not the
correct way. I have seen a lot of articles mentioning about the
nightmare of extension method like maintenance issues, naming conflicts,
etc... but I haven't found the article that mention the other way round.
Inheritance creates a very close relationship between your new class and
the base class. It also _creates a whole new class_! Generics are
complicated enough, where you get a whole new class just by using a
different type parameter. So to create yet another whole new class just
to add a single method just compounds that issue.

It seems fine to me.
It's my opinion that these general rules of thumb apply with extra
strength to the built-in classes, at least those not specifically
designed for inheritance in mind (e.g. abstract classes like Stream,
CollectionBase, etc.), because the benefits tend not outweigh the added
complexity. It's not a hard-and-fast rule -- one thing inheritance
allows you to do is store additional data with the instance, and that's
a lot more complicated to do without inheritance -- but it should be the
guiding principle, going against it only when one has considered
carefully the reasons and alternatives and has decided that inheritance
is clearly the best solution.
....

Another issue is that sometimes people try to inherit a collection class
to hide members of the base class. That doesn't seem to be the case
here, but it's another example of where inheriting the class is a bad
idea. Member hiding is almost never the right approach, since in spite
of the use of the word "hide", it's not a security feature at all (i.e.
you can hide a member, but the hidden member is always still accessible
to code that wants it or, worse, to code that doesn't realize there's a
derived class hiding the member).

Member hiding is achived through composition and it is different from
inheritance. So, the above statement is not valid for our discussion.
Basically, the general OOP rule is that if there's a simple way to avoid
inheriting a class, then do that instead of inheriting a class.
Inheritance should be used where it makes the code _better_ in some
observable way. That is not the case here.


Just because a class isn't sealed, that doesn't mean that inheriting the
class is always the right way to a solution.

Pete

Your point is still not strong enough to convince me. But you have your
view and I have mine. I sometimes, does not limit myself to OOP rules.
The world is definitely open for someone to explore. Yeah, since I have
lot of free time right now, maybe I should study it deeper. Time for a
little googling. Thanks for your opinion.

Regards.
 
P

Peter Duniho

But, solving through extension methods is also in my opinion not the
correct way. I have seen a lot of articles mentioning about the
nightmare of extension method like maintenance issues, naming conflicts,
etc... but I haven't found the article that mention the other way round.

Extension methods are useful and safe enough that Microsoft built a whole
new feature around them. As you already pointed out, they are nothing
more than "syntactic sugar" for a plain old static method, which would be
the usual alternative one would choose here.
[...]
Member hiding is achived through composition and it is different from
inheritance. So, the above statement is not valid for our discussion.
[...]

Member hiding has nothing at all to do with composition. It's entirely
about inheritance, and can take place only in that context. You should
get your OOP fundamentals straight before you start debating the subtler
points.

Pete
 
K

kndg

Peter said:
Extension methods are useful and safe enough that Microsoft built a
whole new feature around them. As you already pointed out, they are
nothing more than "syntactic sugar" for a plain old static method, which
would be the usual alternative one would choose here.

You are againts Microsoft guidelines for extension methods. Quote from
MSDN: http://msdn.microsoft.com/en-us/library/bb383977.aspx

"In general, we recommend that you implement extension methods sparingly
and only when you have to. Whenever possible, client code that must
extend an existing type should do so by creating a new type derived from
the existing type."
[...]
Member hiding is achived through composition and it is different from
inheritance. So, the above statement is not valid for our discussion.
[...]

Member hiding has nothing at all to do with composition. It's entirely
about inheritance, and can take place only in that context. You should
get your OOP fundamentals straight before you start debating the subtler
points.

Are you referring to the keyword "new"? But whenever I see the keyword
"new" on the derived class, then I would question their decision to
inherit a base class at all. If you are referring something else, care
to share the knowledge?
 
P

Peter Duniho

You are againts Microsoft guidelines for extension methods. Quote from
MSDN: http://msdn.microsoft.com/en-us/library/bb383977.aspx

"In general, we recommend that you implement extension methods sparingly
and only when you have to. Whenever possible, client code that must
extend an existing type should do so by creating a new type derived from
the existing type."

"Client code that MUST extend an existing type should so so by...". This
is not a situation where client code MUST extend the type.
[...]
Member hiding is achived through composition and it is different from
inheritance. So, the above statement is not valid for our discussion.
[...]
Member hiding has nothing at all to do with composition. It's
entirely about inheritance, and can take place only in that context.
You should get your OOP fundamentals straight before you start debating
the subtler points.

Are you referring to the keyword "new"?

Of course I am. That's what member hiding is. There's nothing else.
But whenever I see the keyword "new" on the derived class, then I would
question their decision to inherit a base class at all.

It's not necessarily the inheritance that's the issue (but as I've stated,
inheritance should be avoided), it's the hiding. You can properly inherit
a class without hiding its members.

Pete
 
B

Ben Voigt [C++ MVP]

[...]
Member hiding is achived through composition and it is different from
inheritance. So, the above statement is not valid for our discussion.
[...]

Member hiding has nothing at all to do with composition. It's entirely
about inheritance, and can take place only in that context. You should
get your OOP fundamentals straight before you start debating the subtler
points.

Composition hides members just fine. If the instance is private, then all
the member functions are inaccessible.
Are you referring to the keyword "new"? But whenever I see the keyword
"new" on the derived class, then I would question their decision to
inherit a base class at all. If you are referring something else, care to
share the knowledge?

"new" provides only ineffective hiding. If you want to inherit some
behavior and hide other members, composition is the way to go.
 
P

Peter Duniho

[...]
Member hiding is achived through composition and it is different from
inheritance. So, the above statement is not valid for our discussion.
[...]

Member hiding has nothing at all to do with composition. It's
entirely about inheritance, and can take place only in that context.
You should get your OOP fundamentals straight before you start
debating the subtler points.

Composition hides members just fine. If the instance is private, then
all the member functions are inaccessible.

But that's not what the phrase "member hiding" means.

Just because the word "hide" has a broader meaning in the English
language, that doesn't mean that's what's relevant here. Otherwise, we're
going to have all sorts of trouble with these words ("new", "composition",
"inheritance", etc.)
"new" provides only ineffective hiding. If you want to inherit some
behavior and hide other members, composition is the way to go.

In other words, avoid inheritance (which was my point in the first place).

Pete
 
B

Ben Voigt [C++ MVP]

Peter Duniho said:
[...]
Member hiding is achived through composition and it is different from
inheritance. So, the above statement is not valid for our discussion.
[...]

Member hiding has nothing at all to do with composition. It's
entirely about inheritance, and can take place only in that context.
You should get your OOP fundamentals straight before you start
debating the subtler points.

Composition hides members just fine. If the instance is private, then
all the member functions are inaccessible.

But that's not what the phrase "member hiding" means.

Just because the word "hide" has a broader meaning in the English
language, that doesn't mean that's what's relevant here. Otherwise, we're
going to have all sorts of trouble with these words ("new", "composition",
"inheritance", etc.)

I don't think it's C# vs English but C# vs standard CompSci terminology for
OOP. For example, in CompSci one talks about interface inheritance vs
behavior inheritance, in C# one talks about implementation vs inheritance.

So it's somewhat ill advised to lambaste someone with "get your OOP
fundamentals straight" when they are using what is, as near as I can tell,
accepted terminology within the OOP computer science community.
 
P

Peter Duniho

[...]
So it's somewhat ill advised to lambaste someone with "get your OOP
fundamentals straight" when they are using what is, as near as I can
tell, accepted terminology within the OOP computer science community.

Granted, OOP wasn't even part of the curriculum when I got my CS degree.
But I've never seen the term "member hiding" applied to anything except
members of inherited classes, in the context of C# or elsewhere. I didn't
find any obvious counter-examples using Google either.

In CS, there is the concept of "information hiding", which of course is a
more general concept. But hiding _members_ is about inheritance, as
that's the only context in which you can hide a specific member of a class
(as opposed to the entire instance itself) that wasn't previously hidden
(i.e. "hiding" isn't related to other accessibility control, such as
"private" vs. "public" in C# and other languages).

In any case, all of this is tangential to the original question, which is
"should code inherit the List<T> class just so that it can create a
special-purpose convenience Add() method?", and other than a person's
stated desire to use inheritance wherever possible (which is pretty much
the opposite of what one should do, in my opinion) there's nothing at all
to suggest that the answer to that question is in the affirmative.

Pete
 
K

kndg

Peter said:
"Client code that MUST extend an existing type should so so by...".
This is not a situation where client code MUST extend the type.

Why? In what situation where you think inheritance is a must? My current
practice is to always favor inheritance over extension methods. I'm
always limiting my usage of extension methods for helper method only (a
method that doesn't change the internal state of underlying type) which
is not the case here. Is there any concrete guidelines?
 
P

Peter Duniho

Why? In what situation where you think inheritance is a must?

There are lots of examples, most of which involve polymorphism (e.g.
inheriting System.IO.Stream, System.Windows.Forms.Control, etc.)

My current practice is to always favor inheritance over extension
methods.

Yes, you've already made that very clear.
I'm always limiting my usage of extension methods for helper method only
(a method that doesn't change the internal state of underlying type)
which is not the case here. Is there any concrete guidelines?

How is this convenience "Add()" method not a "helper method"? Why does a
"helper method" necessarily not mutate the instance of the object on which
it operates? Why should extension methods be limited only to "helper
methods", however you define that?

As far as whether there are concrete guidelines, you've posted a link to
the guidelines as Microsoft appears to provide them, and those guidelines
are not inconsistent with my advice. They have some important caveats to
consider when dealing with extension methods, but those caveats don't
apply in this particular scenario.

Pete
 
K

kndg

Peter said:
[...]
In any case, all of this is tangential to the original question, which
is "should code inherit the List<T> class just so that it can create a
special-purpose convenience Add() method?", and other than a person's
stated desire to use inheritance wherever possible (which is pretty much
the opposite of what one should do, in my opinion) there's nothing at
all to suggest that the answer to that question is in the affirmative.

Ok, consider below example:

Suppose someone is using List<T> and would like to add a feature that a
list can be bulk-updated (I don't know whether this feature already
exist or not, but well for the sake of example). He wants his BulkUpdate
method to just update the list and stop when it is invalid. Instead of
inheritance, he choose extension methods.

static class MyExtension
{
public static void BulkUpdate<T>(this List<T> list, IList<T> source,
int index)
{
for (int i = 0; i < source.Count; i++)
{
if (index + i > list.Count - 1) return;
list[index + i] = source;
}
}
}

class MyClass
{
static void Main(string[] args)
{
var list = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list.ForEach(Console.WriteLine);
Console.WriteLine();
list.BulkUpdate(new[] { 100, 200, 300, 400}, 8);
list.ForEach(Console.WriteLine);

Console.ReadKey();
}
}

So far so good, his method works.

But what if Microsoft is adding bulk-update feature on their next
version? Since I'm not the author, I'm faking the List<T> class as below

FakeList<T> : List<T>
{
public void BulkUpdate(IList<T> source, int index)
{
if (source.Count + index > Count)
{
throw new ArgumentException();
}

for (int i = 0; i < source.Count; i++)
{
this[index + i] = source;
}
}
}

The difference is, this new implementation checks the argument before
proceed the update.

When that someone updated their framework to the new version of List<T>
and compile his code, the code compiles just fine but watch it crumble
at runtime. If he ever choose inheritance over extension, the compiler
is very helpful to warn that there is a new version and let the author
to decide.

Regards.
 
P

Peter Duniho

Ok, consider below example:

Suppose someone is using List<T> and would like to add a feature that a
list can be bulk-updated (I don't know whether this feature already
exist or not, but well for the sake of example). He wants his BulkUpdate
method to just update the list and stop when it is invalid. Instead of
inheritance, he choose extension methods. [...]

There are a number of reasons why your contrived example isn't applicable,
not the least of which being that IT'S NOT THE SCENARIO BEING DISCUSSED
HERE!

Furthermore, as we have already discussed, Microsoft does warn against
_specific_ scenarios when using extension methods, such as when there is a
possibility the extension method may be duplicated in the extended class
in the future. But there is exactly a 0% chance that .NET would add a
convenience method Add(string strName, int id) to the List<MyClass>
class. None. No chance, whatsoever.

Even if we were talking about the "BulkUpdate()" method you're talking
about, that's a method I'm very confident would never be added to the
List<T> class. In fact, the chances of _any_ new members being defined in
the List<T> class during the lifetime of .NET are infinitesimally small.
I won't go so far as to say it could never happen, because it's not
provable that it couldn't. But there's really no sensible possibility of
it happening.

Yes, the guidance Microsoft provides is useful. Yes, one should pay
attention to it. But again, there's nothing in that guidance that is
contradiction with the advice I offered the OP earlier, nor with the
statements I've made here since.

Pete
 
K

kndg

Peter said:
[...]
There are a number of reasons why your contrived example isn't
applicable, not the least of which being that IT'S NOT THE SCENARIO
BEING DISCUSSED HERE!

Pete,

I don't know if I had followed the thread differently but...

I'm just asking the OP why he would go the hard way. He had just
searched a 'hack' to get the extension method working on C# 2.0. I had
shown him two alternatives to get it working on C# 2.0.

Then the discussion start when you said that inheriting any class should
be avoided which is contradict to my view. I'm not asking the specific
situation like the problem the OP is having. To me it is like that you
are saying extension methods is a preferable way to extend the
functionality of a type.

Maybe I get it wrong. English is not my native language.
Regards.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Top