Ищу интересные нетривиальные примеры для самообразования.
Нашел интересный пример в книге Эндрю Троелсена Язык программирования С# 2005. Кому интересно, не запуская приложение определить, что выведется в конце.
public class A
{
public int p;
public A(int x)
{
p = x;
}
}
public static void SendA(A a)
{
a.p = 50;
a = new A(11);
}
static int Main()
{
A a = new A(10);
SendA(a);
Console.WriteLine(a.p);
Console.ReadKey();
return 0;
}
Кто знает интересные примеры, прошу выкладывать здесь.
6 июля 2009 в 18:00
Если эта статья википедии не является для тебя авторитетным источником, полазай по ссылкам оттуда. Стратегии передачи параметров описаны очень много где, в т.ч. в куче учебников.
4 июля 2009 в 9:05
Передай параметр "а" по ссылке… явно указав что передается по ссылке (ref) и увидишь разницу…
А типы данных, что ссылочные, что "примитивные" все это объекты, и в любом случае мы используем ссылки на них. Другое дело типы по значению могут являться базовыми для которых четко определена операция "=". И еще разница в том где под них память выделяется.
И я бы не стал сильно верить wikipedia, я с уважением отношусь к этому сайту, но все же… "This article's citation style may be unclear. The references used may be made clearer with a different or consistent style of citation, footnoting, or external linking."…
4 июля 2009 в 7:03
Приведенная статья использует не общепринятую терминологию, а книжка у меня не открывается.
Вот общепринятая: //en.wikipedia.org/wiki/Evaluation_strategy
Передача по значению – call by value.
При этом значение аргумента копируется, и функция не может изменить значение в контексте вызывающего.
Передача по ссылке – call by reference.
При этом передается не копия значения аргумента, а ссылка на него, и функция может, изменив его, повлиять на значение, видимое вызывающим.
В C#, очевидно, для значений ссылочных типов используется второе, поскольку при передаче значений ссылочного типа функции НЕ осуществляется копирование этого объекта, а передается его адрес, т.е. ссылка на него.
C# также поддерживает передачу по "ссылке на ссылку" с помощью ключевого слова ref – при этом передается ссылка на область памяти, содержащую *адрес* значения (в случае ссылочного типа это адрес объекта, в случае примитивного типа – само значение).
То же самое написано в приведенной тобою статье, но другими словами – в ней значением переменной ссылочного типа называется адрес объекта, на который она указывает, а не сам объект. Это неудачный выбор терминологии с их стороны, т.к. он не согласуется с общепринятым и стирает разницу между двумя принципиально разными типами передачи параметров.
3 июля 2009 в 23:05
Ув. Жека jkff Кирпичев я никак не хотел Вас обидеть и не сомневаюсь в Ваших знаниях, но писать, такое:
> C# все параметры ссылочных типов (т.е. все кроме примитивных типов и >структур, насколько я помню) передаются по ссылке
Согласитесь, что для C# это не верно!!!… Пусть примитивный тип это как я понимаю "Базовый тип характеризуемый значением", возможно это просто разная лексика. НО почему передаются по ссылке???? В С# по-умолчанию передается по значению (Если по ссылке то это явно указывается, это же основы).
А по поводу "=" у меня конечно даже слов уже нет…
//msdn.microsoft.com/ru-ru/library/s6938f28.aspx
//books.google.com.ua/books?id=_Er0X0kBAYIC&...
Так что пробелы оказывается тоже есть….
P.S. В последнем примере ответ "01234", НО если закрыть верхний try…
3 июля 2009 в 8:00
По-моему, 01234 будет; кажется, никакого подвоха нет.
3 июля 2009 в 0:02
Народ, подобных примеров, по-моему, достаточно много.. В каждом тесте они встречаются, "что будет на экране, если <много кода>". Кому интересно, загуглите тесты по C#.. =)
2 июля 2009 в 15:02
Есть еще пример…
try
{
try
{
throw new Exception();
}
catch (Exception ex)
{
try
{
Console.Write("0");
throw new Exception();;
}
catch
{
Console.Write("1");
throw;
}
finally
{
Console.Write("2");
}
}
catch
{
Console.Write("3");
}
finally
{
Console.Write("4");
}
2 июля 2009 в 15:01
Ты знаешь, я этот вопрос ряду программистов матерых задал, и почти все ответили 11 =)
2 июля 2009 в 14:05
Чувствую интересный пример я нашел)
2 июля 2009 в 14:05
Да нет, вообще-то, пример тривиальнее некуда Просто он вскрыл пробелы в ряде базовых областей знания у ряда комментаторов
2 июля 2009 в 12:04
to Алексей Тимофеев
Да, кстати, если уж на то пошло. то в C# вообще нету ссылок на области памяти, а есть идентификаторы объектов, по которым дальше и идет связывание.
Так что если Вы пытаетесь писать правильно, то и пишите не "копия адреса ссылки", а "копия идентификатора объекта, ссылающегося на область памяти"
2 июля 2009 в 11:01
Алексей,ты жжошь; иди учи матчасть. Если ты не знаешь, что такое примитивный тип, формальный параметр и чем отличаются имена от значений, то твои знания пока явно недостаточны, чтобы ты имел основания так громко возмущаться моим комментарием.
2 июля 2009 в 11:00
to Алексей Тимофеев
Шел бы ты сам учить ООП…
>> (а не ссылка на этот адрес, не забываем что процедура static)
ээ, т.е. если процедура static то передается не ссылка на адрес? бред!
убираю static
A a = new A(10);
a,SendA(a);
и тоже самое…
>>понятие "примитивный тип" вообще не понимаю
читай книжки… умные.. к примеру Рихтера того же
primitive types – типы, которые поддерживаются компилятором напрямую
>> 2. (Операция "=" в C# не перегружена и запись "a = b" означает "связать имя a со значением b") – где такое написано???????? = – это присвоение!!!
Фразы из контекста дергать – явно не красиво.. читай дальше внимательнее
2 июля 2009 в 10:01
Все очень просто и ничего здесь странного….
1. Первоначально в Main создается объект класса "А" и записывается в переменную "а" (которая является ссылкой, т.е. АДРЕСОМ на экземпляр объекта), в этом экземпляре указывается опять-таки адрес на то место где хранится значение переменной "р" (т.к. все объекты ссылочные). Таким образом получили значение 10 при создании объекта.
2. При вызове процедуры SendA ей передается КОПИЯ АДРЕСА на наш объект (а не ссылка на этот адрес, не забываем что процедура static), естественно, что при ссылке через этот адрес к объекту "р" можно изменить его значение (р=50).
3. Далее создаем новый экземпляр объекта (ВТОРОЙ), который естественно записывает значение р=11, НО АДРЕС ЭТОГО ЭКЗЕМПЛЯРА ЗАПИСЫВАЕТСЯ ВКОПИЮ (и дальнейшие изменения переменной "р" не приведут к изменению переменной "р" созданной в Main, т.к. ссылку на ТОТ объект мы уже перезаписали и по сути работаем с другим экземпляром объекта). Таким образом при выводе переменной "р" получаем 50.
Нужно учить основы ООП ))))
P.S. Если бы такое писать на С/С++ и классы занимали бы достаточно памяти, и если процедура вызывалась бы достаточно часто то создавалась бы утечка памяти, что есть плохо…. да и в шарпе такой код создает дополнительную путаницу…
А так пример познавательный, типа "Так плохо делать…." )))
#3
в первой то строке обращаемся к нашему объекту хоть и к копии, т.к. это копия адреса ссылки.
#4
не понятно, что такое состояние?!?!?… а.р=50 т.е.адрес(а).адрес(р)=50
#5
в C# нет понятия "*a", так как объект и так ссылка и вообще все объекты это ссылки
#7
1. понятие "примитивный тип" вообще не понимаю, т.е. если есть где-то значение 50 записанное в переменной "р" – то "р" это сслыка на этот кусок памяти где 50 записано. Используя эту ссылку может изменить это значение (посредством фреймворк)))) )
2.(Операция "=" в C# не перегружена и запись "a = b" означает "связать имя a со значением b") – где такое написано????????= – это присвоение!!!
3.(имя формального параметра..) – что за лексика????? мы о программировании говорим никаких формальных параметров!!!!!!!! все очень конкретно
2 июля 2009 в 8:00
В C# все параметры ссылочных типов (т.е. все кроме примитивных типов и структур, насколько я помню) передаются по ссылке.
Операция "=" в C# не перегружена и запись "a = b" означает "связать имя a со значением b", а не "перезаписать содержимое объекта, с которым связано имя a, значением b".
Поэтому "a = new A(11)" лишь связывает, в контексте процедуры sendA, имя формального параметра "a" со значением "new A(11)", что никак не изменяет значение переданного фактического параметра, и не изменяет то, с каким значением связан идентификатор a в главной процедуре.
2 июля 2009 в 0:04
Действительно, ответ 50. А почему он перезаписывает 10, ведь вроде не по ссылке передаем, и почему не 11?
1 июля 2009 в 23:04
чё-то я не пойму, мож тупой.. В строке "A a = new A(10);" не должно быть случайно " *а " вместо "а" ? оО
1 июля 2009 в 23:01
Ну так да… 11 он его и не сделает…
а a.p = 50; меняет состояние объекта, а не адрес ссылки
1 июля 2009 в 23:00
2Тимур
Параметр в функцию SendA передается не по ссылке, поэтому функция не может его изменить. Следовательно, программа выдаст 10
Хотя, возможно, я ошибаюсь
1 июля 2009 в 22:03
Да 50 должен…
Ну всякие тонкости и у Рихтера можно посмотреть