I'm writing a class that implements ICollection<T>
and ICollection
interfaces.
MSDN says these are a bit different. ICollection<T>.CopyTo
takes a T[]
argument, whereas ICollection.CopyTo
takes a System.Array
argument. There is also a difference between exceptions thrown.
Here is my implementation of the generic method (I believe it's fully functional):
void ICollection<PlcParameter>.CopyTo(PlcParameter[] array, int arrayIndex)
{
if (array == null)
throw new ArgumentNullException("array");
if (arrayIndex < 0)
throw new ArgumentOutOfRangeException("arrayIndex");
if (array.Length - arrayIndex < Count)
throw new ArgumentException("Not enough elements after arrayIndex in the destination array.");
for (int i = 0; i < Count; ++i)
array[i + arrayIndex] = this[i];
}
However, the non-generic version of the method is confusing me a bit. First, how do I check for the following exception condition?
The type of the source ICollection cannot be cast automatically to the type of the destination array.
Second, is there a way to leverage the existing generic implementation to reduce code duplication?
Here is my work-in-progress implementation:
void ICollection.CopyTo(Array array, int index)
{
if (array == null)
throw new ArgumentNullException("array");
if (index < 0)
throw new ArgumentOutOfRangeException("arrayIndex");
if (array.Rank > 1)
throw new ArgumentException("array is multidimensional.");
if (array.Length - index < Count)
throw new ArgumentException("Not enough elements after index in the destination array.");
for (int i = 0; i < Count; ++i)
array.SetValue(this[i], i + index);
}
You've already done most of the work in implementing ICollection<T>.CopyTo
.
There are four possibilities for ICollection.CopyTo
:
ICollection<T>
.ICollection<T>
would have failed.We can handle the first two by calling into ICollection<T>.CopyTo
.
In each of these cases array as PlcParameter[]
will give us a reference to the array, strongly typed.
In each of the latter cases, it won't.
We do want to catch array == null
separately though:
void ICollection.CopyTo(Array array, int index)
{
if (array == null)
throw new ArgumentNullException("array");
PlcParameter[] ppArray = array as PlcParameter[];
if (ppArray == null)
throw new ArgumentException();
((ICollection<PlcParameter>)this).CopyTo(ppArray, index);
}
If you really wanted you could test array.Rank == 1
in the case of ppArray
being null, and change the error message accordingly.
(BTW, why are you explicitly implementing ICollection<PlcParameter>.CopyTo
? it's likely enough to be useful to be work implementing explicitly, so people don't have to cast to all it.)
In the non-generic CopyTo
the following cases can happen:
object[]
: Handle this one as well, especially if T
is a reference type since in this case T[]
can be cast to object[]
KeyValuePair[]
and DictionaryEntry[]
arrays as wellSo in a general case you should use the following implementation:
void ICollection.CopyTo(Array array, int index)
{
if (array != null && array.Rank != 1)
throw new ArgumentException("Only single dimensional arrays are supported for the requested action.", "array");
// 1. call the generic version
T[] typedArray = array as T[];
if (typedArray != null)
{
CopyTo(typedArray, index);
return;
}
// 2. object[]
object[] objectArray = array as object[];
if (objectArray != null)
{
for (int i = 0; i < size; i++)
{
objectArray[index++] = GetElementAt(i);
}
}
throw new ArgumentException("Target array type is not compatible with the type of items in the collection.");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With