views:

255

answers:

3

I have a large project which was originally written in C#1.1 and is now targeting C#2.0. There are several classes which have methods which take an ArrayList parameter I would like to start to move these to accept List<T> as a parameter, but this can't be done all at one time, so I need to accept both parameters.

My main reason for the migration is so that List<> objects will be accepted as parameters, but I would also like to take advantage of type safety.

Have considered

1) Creating overloads and duplicating the code. This has the advantage of allowing me to mark the old style code as obsolete, but obviously duplicating code is bad.

2) Changing the parameter to IEnumerable : This has the advantage of working with both old and new code, but is not type-safe as it will accept List<T1> where it should be List<T2>

3) Re-writing the methods to take a List<T> parameter and writing a thin wrapper which takes an ArrayList parameter and copies the items to a new List<T> and then calls the main method. This also has the advantage of allowing me to mark the old style code as obsolete. It will have a slight performance/GC hit.

4) Creating three overloads. One private method which take IEnumerable and two public wrapper methods (one for ArrayList and one for List<T>) which just call the private method. This also has the advantage of allowing me to mark the old style code as obsolete. Not sure whether it has any dis-advantages other than having three methods.

I am leaning towards 4, but am I overlooking anything?

+6  A: 

Definitely use a variant of #2, where you shoot for IEnumerable<T> rather than List<T>. For those that need more than IEnumerable<T>, your goal should be IList<T>.

For those methods that can migrate to IEnumerable<T>, you can move them to just IEnumerable for the short term, and in this way avoid needing to maintain two copies of the method. Then, after most of your ArrayLists are gone you can complete the move to IEnumerable<T> with very little effort.

Joel Coehoorn
This answer seems to be getting the votes, so I guess it is the winner.Hadn't considered using IEnumerable<T> rather than List<T> but it would be the better option.I think I will follow Joel's advice for now. Maybe if the non-generic methods are still being used in a few months, I'll do what ShuggyCoUk suggests, so the compiler starts complaining.
sgmoore
A: 

I would create a complete suite of IEnumerable<t> (or perhaps IList<t> if you need manipulation rather than enumeration capabilities) parameter methods and make those your default methods that do all of the work. For compatibility with your ArrayList contract, you could then have your original ArrayList methods translate themselves into IEnumerable<t> and call the IEnumerable methods.

Basically shift the work to your more type-safe option and create a facade for your old contract.

Randolpho
A: 

I would add to Joel's excellent answer that you can avoid the copy overhead by, in your transition phase, using the existing method as you 'real' method and simply call from the IEnumerable<T> overload to the IEnumerable one.

This would be a quick and easy change, with almos no binary incompatibility introduced.

You can mark the IEnumerable method with [Obsolete("please move to the generic implementation", false)] (suppressing the warning on the other overload) then steadily move to the 'correct' version.

Once that is done you can convert the real method to one relying on the type safe generics and drop the chaining.

ShuggyCoUk