Потому что «aaa» не шибко-то похоже на int в десятичной системе. Нужно юзать перегруженный Parse с заданным NumberStyles, если хочется сравнивать с 0xAAA, либо TryParse, если «aaa» — всё же строка.
а вообще, есть тоже один нюанс. Если зайти на страницу тестовую, то вылетит на parse ошибка, это да, потому что в querystring будет пусто. Соответственно перекинет на Error.aspx
C «4» всё понятно, && не пускает до ошибочного кода, и редирект на дефолт.
10 — int занимает в памяти меньше, чем long, и привести не получается (вроде так).
Пошли вопросы аля «Я тут написал хрен знает сколько строк кода, а вы без компилятора попробуйте определить, что выведет программа и где именно я спрятал подводный камень». Это уже не интересно. Если задаёте вопросы, то задавайте их по существу.
я, может, совсем чепуху скажу, не пинайте меня, ибо C# я знаю не так глубоко.
Я сейчас попытаюсь объяснить, почему нельзя распаковать boxedI. Когда упаковываем int, создаётся объект, под него выделяется память, нужная для зранения int, когда же мы распаковываем в long без создания переменной, то у нас не хватает памяти, поэтому выпадает эксепшн. Прошу гуру C# не сильно смеяться, если чепуху сказал :)
дело не в нехватке памяти, наоборот, long длинее чем int. память для временного long выделяется на стеке или в регистре, так что с памятью все в порядке.
ошибка возникает просто из-за несоответствия типов — боксированная переменная содержит ссылку на объект-тип int, а не long, поэтому приведение не срабатывает
не знаю, у одного у меня так, или это и есть камень, внутри блока try catch не работают редиректы. Чтобы это исправить, можно отказаться от трайкеч, при парсинге использовать tryparse, при сравнении с aaa использовать просто строки (да и вообще можно везде поставить switch). Если не нашли пути, то переходим на error.aspx
Исправляеться вот так:
long b = Convert.ToInt64(box);
вот так:
long b = (long)(int)box; //не желательно, т.к. мы точно не знаем, что там long/int? итд.
if (object.ReferenceEquals(Request[«ID»], «aaa»)) //true, if ID=«aaa» т.е. сравнение для строк проходит иначе чем для всех остальных объектов.
Просто пример:
var a = «aaa»
object.ReferenceEquals(a, «aaa»); //true
но
a += «a»;
object.ReferenceEquals(a, «aaa»); //false
причина:
у строк оператор += перегружен и он создаст новый экземпляр.
к тому же .NET строки ещё и кэширует.
Ответ:
~/PageA.aspx (присание выше)
~/PageB.aspx //всё ок, если не вдаваться в подробности культурологии и прочего
~/Error.aspx //Invalid Cast Exception
~/Error.aspx //Invalid Cast Exception
Всегда будет перехдить по Response.Redirect("~/Error.aspx"); Т.к. какой то из методов всегда генерирует исключение. Которое перехватывает наш try{}catch{}
Не так давно в каком то тематическом блоге данная ситуация разбиралась.
видимо, не так часто, поскольку на хабре я не нашел нужного топика, и как видите, пока еще никто не ответил, почему так
а Ваше предложение тоже не очень устраивает, потому что тогда будут возникать события контролов типа OnChange и т.д. Я же когда пишу Redirect, хочу этого избежать
это такой тонкий пиар? )
решение проблемы можно найти где угодно, но главное — понять принцип, почему данный код работает именно так
а решение с false все еще не устраивает )
:) а я и не собираюсь делать, чтобы кого-то что-то устраивало. Пиарить GotDotNet, думаю, не нужно, про него и так все хорошо знают. Вот еще советы:
Если хотите продолжать, делайте топик хотя бы закрытый. Как думаете, если тут php-разработчики сидят, они хотят видеть такие «этюды» каждый день? А если по каждому языку такой «этюд»?
Для меня таких «этюдов» море на GotDotNet, я лучше потрачу свои силы, чтобы действительно народу помочь, а не поломать мозг в соревновании у кого длиннее ;)
Не знаю. Может и это полезно. Например, этот «этюд» и меня заинтересовал.
В любом случае — делайте их по крайней мере внутри .net блога. Так тут будут только заинтересованные.
можно было бы задать в качестве следующего этюда )
пока я вижу только одно решение — дублировать в .NET в закрытом режиме и в персональном блоге — в открытом. Приемлемо ли такое на хабре?
многих и персональный лог не устроит, ибо он тоже может попасть на главную. В списке новых топиков он появтся. Продолжайте транслировать в блог .Net, ничего плохого в том, что в дотнете появляются новые интересные топики, я не вижу. :)
1. Test.aspx?ID=aaa — ~/PageA.aspx (сравниваются значения string)
2. Test.aspx?ID=bbb — ~/PageB.aspx
3. Test.aspx?ID=4 — ~/PageDafault.aspx (из-за первого условия в if)
4. Test.aspx?ID=10 — ~/Error.aspx (ошибка анбоксинга, long не int, должно быть точное соответствие)
а вот исправление — это больше вопрос философский :) если просто исправить для 10, то поменять long на int — просто не будет редиректа на Error.aspx. А все остальное — это от стремления к прекрасному зависит.
ответ неверный
конечно, знания ASP.NET тут играют существенную роль, но можно попытаться и общими методами догадаться
что по-Вашему делает Redirect и как бы Вы его написали, если бы Вам пришлось это делать?
Ну, если с минимальными изменениями, можно забить на это исключение
catch (ThreadAbortException)
{
}
catch (Exception)
{
Response.Redirect("~/Error.aspx");
}
Если я не ошибаюсь при таком решении сработает только запрос Test.aspx?ID=bbb (приведет на страницу "~/PageB.aspx")
В остальных случаях будет немного иначе:
— Test.aspx?ID=aaa приведет на Error.aspx — сравнение (object.ReferenceEquals(Request[«ID»], «aaa»)) естественно даст false и код соотвественно попадет на int i = int.Parse(Request[«ID»]), где выскочит FormatException.
— Test.aspx?ID=10 тоже приведет на Error.aspx — на месте ((long)boxedI == 10 выскочит InvalidCastException.
— Test.aspx?ID=4 приведет на PageDefault.aspx — тут немного интереснее. Вообще по аналогии с предыдущем запросом должна также сработать InvalidCastException, но так как первая часть условия (i > 5) при сравнении с 4 даст false, то в связи со спецификой оператора && (сокращенное вычисление) вторая часть условия проверяться вообще не будет. Если заменить строку сравнения на
((i > 5) & ((long)boxedI == 10)) — то выдаст ожидаемую InvalidCastException
Мне кажется по логике задачи ожидалась несколько другая функциональность.
логику Вы описали безупречно, но она надуманная, и предназначена, чтобы люди отвекли свое внимание и не заметили настоящего подвоха )
собственно, интернирование строк, неявное/явное приведение типа и короткая схема вычисления логических выражений — отвлекающий маневр, не более
смотрите ветку сразу после этой
мне-то оно точно было интересным, когда я столкнулся с таким поведением )
а все запутывания помогают лучше передать реальную ситуацию
вот если бы я написал
Запустил таки код. Всегда на error.
Вообще говоря, я не понимаю, нафига этот квест с заведомо отвлекающей хернёй типа ReferenceEquals и боксинга, если решение по типу исключения гуглится в минуту.
ну кстати, посмотрите сколько на ReferenceEquals было вариантов, причем неправильных
конечно, я овлекающие вещи поставил, потому что не хотел, чтоб ответ через минуту появился )
если это ответ на самый первый вопрос, то он неправильный
хотя насчет интернирования, сравнения, короткой схемы логики и анбоксинга Вы правы )
кстати, интернировать можно и явно, а не только на этапе компиляции, но я почти уверен, что Вы это тоже знаете
ну допустим, Вы считаете эти знания необязательными, я же придерживаюсь противоположной точки зрения )
как показала практика моих этюдов ), на хабре мои задачи решают довольно быстро, так что не вижу смысла здесь давать более простые. наоборот, стоит повышать уровень здесь сидящих, а не понижать
хотя если Вы уверены в своей задумке — никто не мешает попробовать ))
ну второй известный прикол, все Ваши константы типа int, потому будет переполнение, несмотря на то, что тип переменной long
насчет результата компиляции не уверен, константы вычисляются в это время, но работатет ли там соответствующая опция — не знаю
исправить можно либо так: long value2 = 10L * 1000 * 10000 * 100000;
либо так: long value2 = unchecked(10 * 1000 * 10000 * 100000);
зависит от того, что именно Вам требуется
C#: Этюды, часть 3