:: Не фоксом единым
C# индексатор с params
S-type

Сообщений: 2969
Дата регистрации: 24.04.2004
Как говорил профессор Преображенский

Цитата:
И — боже вас сохрани — не читайте до обеда советских газет.

Читал Хабрахабр, наткнулся habrahabr.ru :

Цитата:
Индексаторы могут использовать params параметры

В общем то, индексаторы в реальной жизни применял всего один раз. И, даже не задумывался, что можно для объявления индексатора использовать params. Решил попробовать:


Действительно, всё работает! Понятно, что какой либо практической пользы от этого вряд ли когда то можно получить. Но, не в этом вопрос. Единственное, что не нравится - это конструкция в set:

set
{
int k = 0;
foreach (T j in value)
{
arr[i[k++]] = j;
}
}

Можно как то это сделать покрасивее? Например, лямбды как то прикрутить. Зачем - не спрашивайте, сам не знаю



[i]Исправлено 1 раз(а). Последнее : S-type, 10.02.17 16:00
Ratings: 0 negative/0 positive
Re: C# индексатор с params
Рома

Сообщений: 1079
Дата регистрации: 06.06.2001
S-type
Например, лямбды как то прикрутить.

i.Select((iv, ii) =>
{
arr[iv] = value[ii];
return false;
}).Any();

Может и красиво, но не эффективно



Исправлено 1 раз(а). Последнее : Рома, 11.02.17 11:10
Ratings: 0 negative/0 positive
Re: C# индексатор с params
Igor Korolyov
Автор

Сообщений: 34580
Дата регистрации: 28.05.2002
Индексатор это не более чем синтаксический сахар, чуть повыше "свойств" стоит (сами "свойства" это тоже синтаксический сахар ). На самом деле и то и другое это просто методы (или пары методов) плюс метаданные "связывающие" их воедино. При том в VB и для "обычных" свойств можно использовать параметры, слава богу в C# это разрешили только для индексаторов.
Чрезмерное увлечение лямбдами, анонимными методами и типами я лично считаю плохой привычкой.
Да, есть места где всё это уместно. Но городить огород там где замечательно справляются старые добрые способы кодирования... Ну это нехорошо.
По крайней мере, если разработчик ни разу не использовал достаточно низкоуровневый декомпилятор (они в большинстве своём стараются "вернуть на место" весь синтаксический сахар из IL кода - вот чисто декомпилятор IL кода честен по максимуму, показывая ВСЁ внутреннее устройство), или не понимает досконально как на самом деле реализовано всё это хозяйство, включая захват переменных и невидимые/служебные классы... Ну тогда он вряд ли сможет адекватно выбрать каким способом лучше всего решать задачу


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: C# индексатор с params
S-type

Сообщений: 2969
Дата регистрации: 24.04.2004
Рома
Может и красиво, но не эффективно

Увы, не работает - ругается на value[ii];

Цитата:
Не удается применить индексирование через [] к выражению типа "IEnumerable<T>".
Ratings: 0 negative/0 positive
Re: C# индексатор с params
Рома

Сообщений: 1079
Дата регистрации: 06.06.2001
Тогда
i.Zip(value, (iv, val) =>
{
arr[iv] = val;
return false;
}).Any();
Ratings: 0 negative/0 positive
Re: C# индексатор с params
S-type

Сообщений: 2969
Дата регистрации: 24.04.2004
Igor Korolyov
Чрезмерное увлечение лямбдами, анонимными методами и типами я лично считаю плохой привычкой.

Согласен полностью.

Но, тут задача на "знание языка". Просто, потренироваться. Каких то конкретных задач нет.



Исправлено 1 раз(а). Последнее : S-type, 12.02.17 13:04
Ratings: 0 negative/0 positive
Re: C# индексатор с params
S-type

Сообщений: 2969
Дата регистрации: 24.04.2004
Рома
Тогда

Вижу Федю, но Вася куда то потерялся...

В общем то, я мыслил примерно в ту же сторону - пытался сделать что то вроде

Array.ForEach(i,(t)=> { arr[t] = что_то(value); });

Но, как брать элементы из value по очереди - непонятно. yield в анонимном блоке указывать нельзя.



Исправлено 2 раз(а). Последнее : S-type, 12.02.17 13:22
Ratings: 0 negative/0 positive
Re: C# индексатор с params
S-type

Сообщений: 2969
Дата регистрации: 24.04.2004
В общем то, можно сформулировать задачу так. В реализации:

int k = 0;
foreach (T j in value)
{
arr[i[k++]] = j;
}

не нравится, что перебор идёт по value. Хотелось бы "плясать" от i (от параметра). Например:

for (int k=0; k<i.Count(); k++)
{
arr[i[k++]] = что_то(value);
}

Но, как из IEnumerable<T> по очереди получать значения - ни разу не понятно.



Исправлено 2 раз(а). Последнее : S-type, 12.02.17 13:21
Ratings: 0 negative/0 positive
Re: C# индексатор с params
Igor Korolyov
Автор

Сообщений: 34580
Дата регистрации: 28.05.2002
Ну раз уж "чисто ради интереса".
Конструкция
foreach (T j in value)
{
arr[i[k++]] = j;
}
При компиляции преобразуется в
IEnumerator<T> enumerator = value.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
T j = enumerator.Current;
arr[i[k++]] = j;
}
}
finally
{
enumerator?.Dispose();
}

Это если value не является массивом - для массива foreach приводится к циклу
for (int ii = 0; ii < array.Length; ii++)
{
T j = array[ii];
...
}

Так что как "по очереди получать значения" предельно ясно должно быть

P.S. Естественно в IL нет никаких for и while - там всё чисто на ветвлениях - условных и безусловных переходах делается
P.P.S. Движок форума скушал индекс i поменял на ii


------------------
WBR, Igor




Исправлено 2 раз(а). Последнее : Igor Korolyov, 12.02.17 16:31
Ratings: 0 negative/0 positive
Re: C# индексатор с params
S-type

Сообщений: 2969
Дата регистрации: 24.04.2004
Igor Korolyov
Ну раз уж "чисто ради интереса".
Конструкция
[...]

Честно говоря - не знал. Спасибо.

Проверил - можно написать так:

get
{
using (IEnumerator<T> enumerator = value.GetEnumerator())
{
for (int k = 0; k < i.Count(); k++)
{
enumerator.MoveNext();
arr[i[k]] = enumerator.Current;
}
}
}

так:

get
{
using (IEnumerator<T> enumerator = value.GetEnumerator())
{
foreach (int k in i)
{
enumerator.MoveNext();
arr[k] = enumerator.Current;
}
}
}

И даже так:

get
{
using (IEnumerator<T> enumerator = value.GetEnumerator())
{
Array.ForEach(i,(t)=> { enumerator.MoveNext(); arr[t] = enumerator.Current; });
}
}

Впрочем, третий вариант - это уже из области "так лучше не делать".



Исправлено 2 раз(а). Последнее : S-type, 13.02.17 13:41
Ratings: 0 negative/0 positive
Re: C# индексатор с params
S-type

Сообщений: 2969
Дата регистрации: 24.04.2004
Igor Korolyov
При компиляции преобразуется в
IEnumerator<T> enumerator = value.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
T j = enumerator.Current;
arr[i[k++]] = j;
}
}
finally
{
enumerator?.Dispose();
}

А почему не в

IEnumerator<T> enumerator = value.GetEnumerator();
try
{
T j;
while (enumerator.MoveNext())
{
j = enumerator.Current;
arr[i[k++]] = j;
}
}
finally
{
enumerator?.Dispose();
}

Иначе говоря, зачем при каждой итерации выделять память, что бы её потом сборщик мусора убирал? Или, компилятор на столько умён, что сам соптимизирует код и вынесет определение переменной из цикла?
Ratings: 0 negative/0 positive
Re: C# индексатор с params
Рома

Сообщений: 1079
Дата регистрации: 06.06.2001
S-type
Иначе говоря, зачем при каждой итерации выделять память, что бы её потом сборщик мусора убирал? Или, компилятор на столько умён, что сам соптимизирует код и вынесет определение переменной из цикла?

Память под ВСЕ локальные переменные будет выделена на стеке при входе в метод
.locals init (
[0] int32 k,
[1] class [mscorlib]System.Collections.Generic.IEnumerator`1<!T>,
[2] !T j
)

И не важно объявляем мы переменную внутри цикла или снаружи. Области видимости локальных переменных контролирует только компилятор C#.
В IL одна область видимости локальной переменной - метод, причем там даже имена не важны - ldloc/stloc работают чисто по индексу переменной
Ratings: 0 negative/0 positive
Re: C# индексатор с params
Igor Korolyov
Автор

Сообщений: 34580
Дата регистрации: 28.05.2002
Вообще есть неплохая статья в тему на хабре (было бы странно если бы про этот "секрет реализации" никто не написал статью )

1) Неаккуратен твой код мастеру чтобы по нраву быть Выкинул Dispose который таки нужен для экземпляра IEnumerator<T> поскольку он IDisposable (в отличие от не-Generic версии IEnumerator).
2) Второй твой вариант как раз и есть то что я писал про трансформацию foreach для массивов Они компилируются в очень близкий IL код - для Release версии, вполне возможно даже в идентичный.
3) Extension метод ForEach я бы не советовал... И не я один blogs.msdn.microsoft.com
Если кратенько - такой цикл обычно предполагает какие-то действия над выбираемым объектом, что может приводить к его изменению (у тебя в примере этого нет, но такой код скорее исключение чем правило для ForEach), а это значит - будут "побочные эффекты" (коллекции вообще весьма болезненно реагируют на изменение хранящихся в них объектов - это не зависит от языка и системы - в том же фоксе, тривиальный цикл закрытия форм по коллекции _VFP.Forms).
В новых версиях фреймворка (начиная с 4.5) даже явно поставили отлов изменения коллекции изнутри делегата передаваемого этому методу - ну в методе применимом к List<T> - для массива то оно чуть проще - но "непредсказуемость поведения" таки может сохраняться. Лучше именно старый добрый foreach цикл (хотя от самой проблемы "изменения коллекции в процессе прохода по ней" это не спасает, конечно) - ибо сие обычно нужно не для "функционального", а для самого что ни на есть "императивного" кодирования - и там более чётко видны потенциальные проблемы.

Открою тебе ещё пару страшных тайн. "Локальные переменные" методов описываются в заголовке метода (в IL коде), и потому в принципе для "выделения памяти" (под указатель, всего лишь под 4/8 байт с "адресом в памяти") нет решительно никакой разницы где декларируется переменная ссылочного типа. Разница есть для компилятора, который по этим самым "фигурным скобкам" (явным или неявным, как то делают некоторые синтаксические конструкции) определяет области видимости переменных, чтобы создать корректный IL код.
Что ещё более интересно, в процессе оптимизации кода "переменная" может вообще исчезнуть Парадигма языка IL основана на использовании "стека вычислителя" - в языке нету "регистров" как в x86/x64/ARM ассемблере, да и прямых обращений к "адресам памяти" там не так уж и много бывает для C# кода - оперирует он данными в "стеке" (если вдруг знаком с тем как устроен FPU в x86 процессорах, то тут очень похоже - но без жёстко прошитого ограничения размера стека в 8 элементов, и без явной интерпретации каждого элемента как "числа" ). И если от одной точки использования "переменной" до другой очень близко, и "в промежутке" слабо используется этот стек, то эта переменная вполне может остаться "виртуальной" - т.е. где-то вначале быть помещена в стек, по ходу дела дублироваться (т.к. команды "использования" данных из стека их, естественно, "вынимают" оттуда, а dup позволяет сделать копию-жертву для очередной инструкции) ну и в конце просто пропадёт - будет извлечена последней из команд где она ещё нужна...
В Debug версиях и все переменные на месте, да ещё и куча nop ("пустых" операций, ничего не делающих) в коде будет сидеть - для простоты работы отладчика и, наверное, всяких его Edit & Continue фишек, но в Release всё гораздо более "сжато".
В вики достаточно неплохо описана общая архитектура IL - правда в англоязычной таки существенно лучше чем в "родной"
en.wikipedia.org
Там в примере как раз хорошо видно где локальные переменные "описываются" Впрочем, если побаловаться с дизассемблером показывающим помимо C#/VB ещё и IL код, то можно массу всего интересного узреть... Конечно про это можно прочесть и в толстенных книгах типа "CLR изнутри" - но наглядность явно страдает


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: C# индексатор с params
S-type

Сообщений: 2969
Дата регистрации: 24.04.2004
Igor Korolyov
1) Неаккуратен твой код мастеру чтобы по нраву быть

Грешен, каюсь... Добавил богоугодный для C# using.
Ratings: 0 negative/0 positive
Re: C# индексатор с params
Igor Korolyov
Автор

Сообщений: 34580
Дата регистрации: 28.05.2002
Кстати, using это тоже синтаксический сахар - на самом деле он переводится примерно в
var resource = некий IDisposable тип
try
{
работаем с resource
}
finally
{
resource?.Disposе();
}
И это IMHO как раз пример полезного синтаксического сахара - код становится не только короче, но и яснее.


------------------
WBR, Igor
Ratings: 0 negative/0 positive


Извините, только зарегистрированные пользователи могут оставлять сообщения в этом форуме.

On-line: 6 (Гостей: 6)

© 2000-2024 Fox Club 
Яндекс.Метрика