Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Нюанс с использованием for


Автор: Idsa 17.4.2007, 17:24
Всегда считал, что в C# при вот таком объявлении:
Код

      for (int i = 0; i < 10; i++)
        ;

область видимости i - внутри цикла.
Вот такая структура тоже работает вполне нормально:
Код

      for (int i = 0; i < 10; i++)
        ;
      for (int i = 0; i < 10; i++)
        ;

Но почему-то smile вот так делать нельзя:
Код

      for (int i = 0; i < 10; i++)
        ;
      int i = 0;
      for (int i = 0; i < 10; i++)
        ;

Пасиму? smile

Автор: skyboy 17.4.2007, 17:29
так строка "int i = 0;"  сделает так, что во втором for'e уже будет не объявление переменной с областью видимости только внутри цикла, а будет редекларация "внешней" по отношению к циклу переменной.
И ошибка, скорее всего, звучит так: "redeclaring of variable i".

Добавлено через 1 минуту и 34 секунды
Цитата(Idsa @  17.4.2007,  16:24 Найти цитируемый пост)
Всегда считал, что в C# при вот таком объявлении:
Код

     for (int i = 0; i < 10; i++)
        ;


область видимости i - внутри цикла.

Ну, так у тебя в коде
Код

 for (int i = 0; i < 10; i++)
        ;
      int i = 0;
      for (int i = 0; i < 10; i++)
        ;

внутри цикла находятся только пустые строки 2 и 5. А строка с инициализацией(3) - вне обоих циклов. 

Автор: Void 17.4.2007, 17:32
Нельзя перекрывать локальную переменную другой с таким же именем.
Код
class A
{
    int x;
    
    void foo()
    {
        int x; // OK
        {
            int x; // error
        }
    }
}

Точные правила надо смотреть в спецификации…

Автор: Idsa 17.4.2007, 17:33
Прошу прощения: приведенный сначала нерабочий код неработает по вполне понятным причинам, а вот мне интересно, почему не работает вот это кусок:
Код

 for (int i = 0; i < 10; i++)
        ;
      int i = 0;
      for (i = 0; i < 10; i++)
        ;

Автор: mr.DUDA 17.4.2007, 18:29
Ответ, вероятно, искать нужно в спецификации C#. Лично мне самому интересно, какая причина того что переменную цикла нельзя объявлять вне оператора for.

Автор: Exception 17.4.2007, 22:26
Цитата(mr.DUDA @  17.4.2007,  19:29 Найти цитируемый пост)
Ответ, вероятно, искать нужно в спецификации C#.


Ничего такого http://msdn2.microsoft.com/en-us/library/aa691276(vs.71).aspx.

Автор: SLeN 18.4.2007, 00:34
Цитата(mr.DUDA @ 17.4.2007,  18:29)
 Лично мне самому интересно, какая причина того что переменную цикла нельзя объявлять вне оператора for.

Объявить то можно, только до цикла. 

Код

            int i = 10;
            for (i = 0; i < 10; i++) { }


Прекрасно пройдет.

Но вот после объявления в for ее уже не объявить хотя и считается что ее нет в  области видимости

Код

            for (int i = 0; i < 10; i++) { }
            int i = 0;
            Console.WriteLine(i);


Так компилятор ругается что она уже обвленна

Код


            for (int i = 0; i < 10; i++) { }
            //int i = 0;
            Console.WriteLine(i);


а так не верит в ее существование
прикольно  smile 

Автор: Retro 18.4.2007, 01:12
Цитата(Void @  17.4.2007,  16:32 Найти цитируемый пост)
Нельзя перекрывать локальную переменную другой с таким же именем.

Ага.

Цитата(mr.DUDA @  17.4.2007,  17:29 Найти цитируемый пост)
Ответ, вероятно, искать нужно в спецификации C#. Лично мне самому интересно, какая причина того что переменную цикла нельзя объявлять вне оператора for. 

Почему переменная цикла?
Насколько я помню, еще по Си, переменная объявленная в теле цикла является локальной переменной всей функции. Перекрыть локальную переменную можно такой же(с тем же именем) но объявленной глобально. Или в C# это не должно соблюдаться?

Это называется, если не изменяет память, - multiple declaration.




Автор: sergejzr 18.4.2007, 01:20
В Вижуал С++ такая же байда и это совсем не весело. Потому что на самом деле ничего не перекрывается. Одна переменная принадлежит одному циклу, другая другому, какое может быть пересечение?
gcc нормально обращается с этим, ява компилер тоже.

Автор: Retro 18.4.2007, 01:32
Цитата(sergejzr @  18.4.2007,  00:20 Найти цитируемый пост)
Потому что на самом деле ничего не перекрывается.

Действительно, в БорландСи такое:
Код

for (int i = 0; i < 10; i++)
                ;
            i = 1;

компилится на ура.

А в студии(на C#) нифига, пишет - The name 'i' does not exist in the current context.

Что творится?

Добавлено через 1 минуту и 38 секунд
Рано я радовался, что C# так похож на С, нюансы, однако, прорисовываются. Будем учить.

Автор: Medved 18.4.2007, 01:49
MS учит программистов правилам хорошего кода.


Автор: Retro 18.4.2007, 01:56
Код

for (int i = 0; i < 10; i++)
                ;
         int   i = 1;

Вот, ругается - 

Цитата

Error    1    A local variable named 'i' cannot be declared in this scope because it would give a different meaning to 'i', which is already used in a 'child' scope to denote something else


Добавлено через 3 минуты и 12 секунд
На хелп ошибки выдает:

Цитата

Error Message 
A local variable named 'var' cannot be declared in this scope because it would give a different meaning to 'var', which is already used in a 'parent or current/child' scope to denote something else


A variable declaration hides another declaration that would otherwise be in scope. Rename the variable that is declared on the line that generated CS0136. 

The following sample generates CS0136:

  Copy Code 
// CS0136.cs
namespace MyNamespace
{
   public class MyClass
   {
      public static void Main()
      {
         int i = 0;
         {
            char i = 'a';   // CS0136, hides int i
         }
         i++;
      }
   }
}

 

Автор: Idsa 18.4.2007, 06:59
Цитата(sergejzr @  18.4.2007,  01:20 Найти цитируемый пост)
gcc нормально обращается с этим, ява компилер тоже.

Вот в Яве точно помню, что с этим проблем не было, а вот в C++ 3.1 (просто для примера smile ) переменная, объявленная в цикле, считается локальной для всего метода.

Чисто теоретически возможны 2 варианта: 1. переменная, объявленная в цикле, видима только в цикле 2. переменная, объявленная в цикле, видима во всем методе. C# же смешивает 2 эти варианта smile

Автор: Wanderer2019 18.4.2007, 09:29
вот так отрабатывает корректно  smile 
Код

 private void Form1_Load(object sender, EventArgs e)
        {
            {
                for (int i = 0; i < 10; i++)
                    ;
            }
            {
                int i = 0;
                for (i = 0; i < 10; i++)
                    ;
            }
}

Автор: sergejzr 18.4.2007, 09:44
Цитата(Retro @  18.4.2007,  00:32 Найти цитируемый пост)
Рано я радовался, что C# так похож на С

Это скорее MS, а не разница C / C#

Цитата(Medved @  18.4.2007,  00:49 Найти цитируемый пост)
MS учит программистов правилам хорошего кода.

Не понимаю, что в этом случае хорошего smile

Цитата(Wanderer2019 @  18.4.2007,  08:29 Найти цитируемый пост)
вот так отрабатывает корректно

Спасибо! Наглядный пример, что задумано так, а реализовано эдак smile

Автор: mr.DUDA 18.4.2007, 09:48
Что-то подсказывает мне, дело тут в "parent/child scope", по-видимому for открывает child scope уже начиная с объявления переменной цикла...  smile 

Автор: Naum 18.4.2007, 13:03
Цитата(mr.DUDA @  18.4.2007,  10:48 Найти цитируемый пост)
по-видимому for открывает child scope уже начиная с объявления переменной цикла...

Ессессно. А вы как думали? И вообще я не понимаю о чем вы спорите?
Почему-то то, что конструкция вида
Код

{
   int i;
   while (i < 10)
   {
       i++;
   }
}
int i;

не компилится, никого не смущает. А стоило поменять while на for то уже начинаются распри.  smile 

Автор: sergejzr 18.4.2007, 13:10
Цитата(Naum @  18.4.2007,  12:03 Найти цитируемый пост)
не компилится, никого не смущает

почему ты так думаешь?

Автор: Naum 18.4.2007, 13:24
sergejzr, скорее всего это сделано для компилятора. И очень полезно для программистов. Очень легко можно запутаться, если в разных скопах будут переменные с одинаковыми именами.

Автор: sergejzr 18.4.2007, 14:44
С другой стороны я часто пользуюсь переменной i в циклах (думаю не я один). Почему я должен выдумывать для каждого цикла новую переменную, или определять её в начале скопа? И то и другое - неудобно и не нужно.

Автор: Exception 18.4.2007, 15:52
Цитата(sergejzr @  18.4.2007,  15:44 Найти цитируемый пост)
очему я должен выдумывать для каждого цикла новую переменную


Так разве

Код
for (int i = 0; i < 5; i++);
for (int i = 0; i < 5; i++);


не скомплируется?

Автор: sergejzr 18.4.2007, 15:59
В VC++ нет. Насчёт шарпа не знаю.

Автор: Naum 18.4.2007, 16:21
Во-первых, в C# это скомпилируется.
Во-вторых, чем неудобно определять переменную в начале скопа, если она у тебя используется во многих циклах?

Добавлено через 2 минуты и 53 секунды
И еще... Больше двух последовательных циклов в одном методе не есть гуд. ;)

Автор: Void 18.4.2007, 16:30
Цитата(sergejzr @  18.4.2007,  17:59 Найти цитируемый пост)
В VC++ нет. Насчёт шарпа не знаю. 

В VC++ 7.1 и новее — скомпилируется.
Код
int main()
{    
    int i;
    for (int i = 0; i < 10; ++i) // всё нормально
        ;
    for (int i = 0; i < 10; ++i) // и снова ничего противозаконного
        ;
    // А вот это уже было бы ошибкой из-за объявления в первой строке
    // int i;
}

Автор: sergejzr 18.4.2007, 16:33
Цитата(Naum @  18.4.2007,  15:21 Найти цитируемый пост)
Во-вторых, чем неудобно определять переменную в начале скопа, если она у тебя используется во многих циклах?

Хотя эта дискуссия для холиваров, но скажу. Такой код неудобно читать. Переменная, от которой ничего не зависит, выносится наверх вместе с "глобальными" этой функции. Просто лишнее отвлечение внимания.


Цитата(Naum @  18.4.2007,  15:21 Найти цитируемый пост)
И еще... Больше двух последовательных циклов в одном методе не есть гуд. ;)

Не есть гуд то кидаться в крайности и  ещё не есть гуд впихивать в стандартные шаблоны нестандартные проблемы. Иногда нужно и несколько последовательных из за поставленной задачи, читаемости кода или чего нибудь ещё.

Автор: Medved 18.4.2007, 19:18
Цитата(sergejzr @  18.4.2007,  12:44 Найти цитируемый пост)
Не понимаю, что в этом случае хорошего 

То, что пытаются скомпилить - извращение. 


Автор: Idsa 19.4.2007, 07:53
Хм... мало того, что вот этот код не компилится:
Код

      for (int i = 0; i < 10; i++)
        ;
      int i;

, так и вот это не компилится:
Код

      for (int i = 0; i < 10; i++)
        ;
      Console.WriteLine(i);

Я совсем запутался smile

Автор: sergejzr 19.4.2007, 09:39
Idsa, это-от понятно. Переменная i определена только в цикле и не определена вне его.

Автор: Idsa 19.4.2007, 09:50
Цитата(sergejzr @  19.4.2007,  09:39 Найти цитируемый пост)
Idsa, это-от понятно. Переменная i определена только в цикле и не определена вне его.

Это было бы так, если не учитывать предыдущий пример. Получается, что первый кусок кода говорит, что переменная i уже объявлена в данном scope. Тогда мы во втором примере, учитывая это, пытаемся заюзать эту переменную... но нам говорят, что переменной нет в данном scope.

Автор: Naum 19.4.2007, 10:10
Цитата(Idsa @  19.4.2007,  10:50 Найти цитируемый пост)
что переменная i уже объявлена в данном scope.

Читай внимательнее соообщения
Цитата

Error    1    A local variable named 'i' cannot be declared in this scope because it would give a different meaning to 'i', which is already used in a 'child' scope to denote something else

Значит, что переменная объявлена не в этом скопе а в дочернем. Что запрещено.
Нельзя объявлять переменную с одним и тем же именем в скопах находящихся на одной ветке вложенности. Нельзя и все. Так решили мс.
sergejzr, теперь я скажу только за C#.
Idsa, я так и не понимаю, если не будешь пользоваться переменной во внешнем скопе, нафига тебе объявлять ее во внешнем скопе.
Цитата(Exception @  18.4.2007,  16:52 Найти цитируемый пост)
for (int i = 0; i < 5; i++);
for (int i = 0; i < 5; i++);

этот код запросто скомпилится в C#.

Если же ты будешь использовать переменную во внешнем скопе, то объявление ее во внутреннем скопе может запросто тебя запутать.
Код

int i = 0;
for (int i = 0; i < 10; i++)
{
   DoSomething();
}
AnyMethod(i);

Другой программист (да даже и ты дня через два) можешь не заметить, что в цикле ты объявляешь новую переменную (int такое маленькое слово smile). И какое значение у тебя передается AnyMethod? 0 или 10?
З.Ы. (Опять же только для шарпистов). 
Подобный топик, ИМХО, похож на вопрос типа: "А почему программисты не используют goto?".
Я свое ИМХО высказал.  smile Больше писать в этот топик не буду.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)