Как реализовать метод ICollection.CopyTo?
Я пишу класс, который реализует интерфейсы ICollection<T>
и ICollection
.
MSDN говорит, что они немного разные. ICollection<T>.CopyTo
принимает аргумент T[]
, тогда как ICollection.CopyTo
принимает аргумент System.Array
. Существует также разница между исключениями.
Вот моя реализация универсального метода (я считаю, что он полностью функциональный):
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];
}
Однако, не общий вариант метода немного меня путает. Во-первых, , как я могу проверить следующее условие исключения?
Тип источника ICollection не может быть автоматически добавлен к типу целевого массива.
Во-вторых, существует ли способ использовать существующую общую реализацию, чтобы уменьшить дублирование кода?
Вот моя работа в процессе выполнения:
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);
}
Ответы
Ответ 1
Вы уже выполнили большую часть работы по реализации ICollection<T>.CopyTo
.
Существует четыре возможности для ICollection.CopyTo
:
- Он будет работать так же, как
ICollection<T>
.
- Это приведет к ошибке по той причине, что
ICollection<T>
не удался.
- Он будет терпеть неудачу из-за несоответствия ранга.
- Он будет терпеть неудачу из-за несоответствия типов.
Мы можем обрабатывать первые два, вызывая в ICollection<T>.CopyTo
.
В каждом из этих случаев array as PlcParameter[]
даст нам ссылку на массив, строго типизированный.
В каждом из последних случаев это не будет.
Мы хотим поймать array == null
отдельно, хотя:
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);
}
Если вы действительно хотели, вы могли бы протестировать array.Rank == 1
в случае, если ppArray
имеет значение null, и соответствующим образом изменить сообщение об ошибке.
(Кстати, почему вы явно реализуете ICollection<PlcParameter>.CopyTo
? это, вероятно, достаточно, чтобы быть полезной для явной работы работы, поэтому людям не нужно бросать все это.)
Ответ 2
В не-generic CopyTo
могут случиться следующие случаи:
- Типы фактически соответствуют: вызов общей версии
- Массив
object[]
: дескриптор этого, особенно если T
является ссылочным типом, так как в этом случае T[]
можно отнести к object[]
- Если ваша коллекция является словарем, вы можете обрабатывать массивы
KeyValuePair[]
и DictionaryEntry[]
, а также
Итак, в общем случае вы должны использовать следующую реализацию:
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.");
}