Comments 35
Немного поправлю — это не особенность C#, но особенность .NET. И весьма логичная.
Не то чтобы я хочу поспорить, но интересно, почему вы считаете это логичнее, чем возвращать -1?
Ответ, по-моему мнению, был дан в статье…
1) языки программирования «считающие» начало «стандартных» массивов с 1 -> выдавать 0 при поиске очень удобно (как и с массивом C#)
2) мы имеем возможность создать массив, нумеруя его, скажем с -3 до 5 -> -1 означает конкретный индекс, а не отсутствие рез-та.
Да, пока писал, в голову пришла мысль, что де, можно было задать в indexOf смещение массива (0 — первый элемент, 1- второй) вне зав-ти от его индексации. Скажем, для приведенного во втором примере массива indexOf == 0 означал бы всего лишь -3 индекс. Но в этом случае опять бы возникла путаница и новые открытия, что де, платформа .NET не возвращает индекс, а возвращает смещение относительно начала. И снова интриги, расследования…
1) языки программирования «считающие» начало «стандартных» массивов с 1 -> выдавать 0 при поиске очень удобно (как и с массивом C#)
2) мы имеем возможность создать массив, нумеруя его, скажем с -3 до 5 -> -1 означает конкретный индекс, а не отсутствие рез-та.
Да, пока писал, в голову пришла мысль, что де, можно было задать в indexOf смещение массива (0 — первый элемент, 1- второй) вне зав-ти от его индексации. Скажем, для приведенного во втором примере массива indexOf == 0 означал бы всего лишь -3 индекс. Но в этом случае опять бы возникла путаница и новые открытия, что де, платформа .NET не возвращает индекс, а возвращает смещение относительно начала. И снова интриги, расследования…
UFO just landed and posted this here
Вероятно, самокрут имел ввиду Nullable в качестве результата для метода indexof. И таки да, я с ним согласен — Nullable тут удобнее ибо есть Null.
Использовать nullable, где будем проводить проверки на наличие значений и доставать их? Думаю, что это не очень изящное решение.
В этом случае лучше воспользоваться идеей C# и назвать это «нештатной» ситуацией и выдавать Exception наподобие OutOfRange. Но опять же это усложнение совершенно простой с точки зрения решаемой задачи функции.
В этом случае лучше воспользоваться идеей C# и назвать это «нештатной» ситуацией и выдавать Exception наподобие OutOfRange. Но опять же это усложнение совершенно простой с точки зрения решаемой задачи функции.
Дело в том, что Nullable — ссылочный тип.
Поэтому, если кто-то пишет оптимальный парсер больших данных, отказываясь загрязнения кучи вырезкой подстрок (Substring и т.п.), работает только с одной большой строкой и индексами на ней, ему придётся отказаться и от такого IndexOf с nullable, сделав свой IndexOf, возвращающий (-1) при неудаче.
Поэтому, если кто-то пишет оптимальный парсер больших данных, отказываясь загрязнения кучи вырезкой подстрок (Substring и т.п.), работает только с одной большой строкой и индексами на ней, ему придётся отказаться и от такого IndexOf с nullable, сделав свой IndexOf, возвращающий (-1) при неудаче.
Nullable — это не ссылочный тип.
Подошло бы тогда и bool IndexOf(T value, out T index)
Дополню топик ссылкой на исходный код этого метода: http://www.dotnetframework.org/, строка 846
Наш метод
Вызывает другой перегруженный метод, в конце которого мы видим (часть кода опустил):
Наш метод
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public static int IndexOf(Array array, Object value) {
if (array==null)
throw new ArgumentNullException("array");
int lb = array.GetLowerBound(0);
return IndexOf(array, value, lb, array.Length);
}
Вызывает другой перегруженный метод, в конце которого мы видим (часть кода опустил):
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public static int IndexOf(Array array, Object value, int startIndex, int count) {
...
// Return one less than the lower bound of the array. This way,
// for arrays with a lower bound of -1 we will not return -1 when the
// item was not found. And for SZArrays (the vast majority), -1 still
// works for them.
return lb-1;
}
Любопытно, что для generic-массивов нет такой особенности:
public static int IndexOf(T[] array, T value)
Member of System.Array
Returns:
The zero-based index of the first occurrence of value within the entire array, if found; otherwise, –1.
И у методов IndexOf где первый параметр типизированный массив IndexOf(T[] ...)
UFO just landed and posted this here
Нет, не дженерик, откройте Array класс, и у него есть методы принимающие T[] в IndexOf и там четко написано, что возвращается -1, а в методах принимающих Array первым параметром, то, что я описал в статье.
Похоже, я всех запутал.
Тип Int32[ ], который я ошибочно назвал generic-массивом, на самом деле не является Generic-типом (по мнению reflection, IsGenericType=false) и наследуется от System.Array. Сам по себе экземпляр типа Array не создаётся без указания типа элементов. Поэтому «не-generic массивов» (объектов типа Array) не бывает.
Тип Int32[ ], который я ошибочно назвал generic-массивом, на самом деле не является Generic-типом (по мнению reflection, IsGenericType=false) и наследуется от System.Array. Сам по себе экземпляр типа Array не создаётся без указания типа элементов. Поэтому «не-generic массивов» (объектов типа Array) не бывает.
Дело в том, что T[] попадает под описание " type [ n ] " и соответственно тип такого массива — ELEMENT_TYPE_SZARRAY, что значит что это одномерный массив с индексацией от нуля.
Вообще автор откопал довольно странные массивы.
Они не совместимы с обычными
Их тип называет себя
Даже оператор индексации
Поэтому вряд ли кто-то столнётся с ними, ещё менее вероятно, что с IndexOf на них.
Они не совместимы с обычными
System.Int32[]
или System.Int32[,]
Их тип называет себя
System.Int32[*]
Даже оператор индексации
array[i]=a
с ними не работает, нужно использовать array.SetValue(a, i);
Поэтому вряд ли кто-то столнётся с ними, ещё менее вероятно, что с IndexOf на них.
* в типе говорит о том, что CLR знает, что это не SZArray (для многомерных звёздочка не пишется, т.к. она была бы везде и не информативна).
Массивы, которые задаются как T[] — всегда индексируются с нуля, т.к. на этом основано куча оптимизаций (для SZArray в CLR есть отдельные команды, которые позволяют с такими массивами эффективнее работать, ибо нет смещения).
Если посмотреть например на сортировку массивов, то в Array.Sort реализованы методы, которые сортируют как T[], так и Array.
Массивы, которые задаются как T[] — всегда индексируются с нуля, т.к. на этом основано куча оптимизаций (для SZArray в CLR есть отдельные команды, которые позволяют с такими массивами эффективнее работать, ибо нет смещения).
Если посмотреть например на сортировку массивов, то в Array.Sort реализованы методы, которые сортируют как T[], так и Array.
Array это все масивы [ ] во всем NET
Возмите тип у int[] и посмотрите какой у него базовый класс. Базовым классом будет аккурат Array.
Он не типизирован, поэтому у него нет индексаторов а доступ только через методы, причем всегда с боксингом для валю типов. Т.е. я откопал довольно не странный массив =)
Возмите тип у int[] и посмотрите какой у него базовый класс. Базовым классом будет аккурат Array.
Он не типизирован, поэтому у него нет индексаторов а доступ только через методы, причем всегда с боксингом для валю типов. Т.е. я откопал довольно не странный массив =)
Multidimensional Array
Array — это абстрактный класс, поэтому факт, что
То есть, не занимаясь интеграцией с чужими языками, вероятность встретить такой массив ничтожна, поэтому я его назвал странным.
System.Int32[*]
, создаваемый через Array.CreateInstance, странный, потому что для него нет поддержки в языке, сравнимой с обычными линейными, двумерными и N-мерными массивами (создание и инициализация через new, индексатор).Array — это абстрактный класс, поэтому факт, что
System.Int32[*]
— потомок Array, ничего особенно не значит (поддержка контракта, не более)То есть, не занимаясь интеграцией с чужими языками, вероятность встретить такой массив ничтожна, поэтому я его назвал странным.
У нас много интроинспекции в инструментарии, и со всеми масивами [ ] работа производится через Array.
А всё-таки, массивы типа
T[*]
живут в проекте? ;)Если есть поле и у него тип это массив [ ] каких то типов заранее неизвестных, то через рефлексию создается как раз Array нужного типа, заполняется через методы и присваивается полю. Для этого Array и является базовым. чтобы можно было работать с масивами имея тип как Type.
Если есть поле и у него тип это массив [ ]
Значит, это обычный массив. Полю типа
int[]
нельзя присвоить массив System.Int32[*]
— несовпадение типов возникнет.Другие перегруженные методы, например
Array.CreateInstance(typeof(int), n1)
,Array.CreateInstance(typeof(int), n1, n2)
,Array.CreateInstance(typeof(int), new[]{n1, n2})
(т.е. без указания массива LowerBounds), создают обычные массивы
System.Int32[]
и System.Int32[,]
Конкретно для пример из статьи, метод может быть такой
Array GetArray() { return new int[] { }; }
Array GetArray() { return new int[] { }; }
UFO just landed and posted this here
Очень жаль, что некоторые воспринимают такие статьи как “капитанство” отбивая всякое желание к написанию, но несмотря на это, в комментариях, порой, всплывает много полезной информации.
Участвуете в конкурсе на самую короткую статью? 50 строк вместе с кодом, круто. На stackoverflow вопросы длиннее.
Sign up to leave a comment.
Интересные моменты, которые вы, возможно, не знали о C# (Array)