Чем отличается объявление переменной в цикле For или out?

#c#

#c#

Вопрос:

  1. Почему метод Calcu1 имеет тот же код, что и метод Calcu2 в ILSpy, в то время как другие нет?

  2. Хотя это разные типы (некоторые из них имеют ссылочный тип, другие — тип значения), почему метод Calcu3 является единственным, который имеет другой хэш-код? Другие объявляют и управляют одной и той же переменной?

     class Program {
    static void Main(string[] args) {
        Calcu8();
    }
    
    static void Calcu1() {
        int single;
        for (int i = 0; i < 10; i  ) {
            single = 5;
            Console.WriteLine(single   i);
        }
    }
    
    //Method Calcu2 has the same code as Method Calcu1 in ILSpy
    static void Calcu2() {
        for (int i = 0; i < 10; i  ) {
            int single = 5;
            Console.WriteLine(single   i);
        }
    }
    
    //class type
    static void Calcu3() {
        for (int i = 0; i < 10; i  ) {
            Student stu = new Student();
            stu.Name = "Tim";
            //not the same
            Console.WriteLine(stu.GetHashCode());
        }
    }
    
    //class type
    static void Calcu4() {
        Student stu = new Student();
        for (int i = 0; i < 10; i  ) {
            stu.Name = "Tim";
            //same
            Console.WriteLine(stu.GetHashCode());
        }
    }
    
    //string
    static void Calcu5() {
        string str = string.Empty;
        for (int i = 0; i < 10; i  ) {
            str = "Hello";
            //same
            Console.WriteLine(str.GetHashCode());
        }
    }
    
    //string
    static void Calcu6() {
        for (int i = 0; i < 10; i  ) {
            string str = string.Empty;
            str = "Hello";
            //same
            Console.WriteLine(str.GetHashCode());
        }
    }
    
    //struct
    static void Calcu7() {
        Person per = new Person();
        for (int i = 0; i < 10; i  ) {
            per.Name = "Tim";
            //same
            Console.WriteLine(per.GetHashCode());
        }
    }
    
    //struct
    static void Calcu8() {
        for (int i = 0; i < 10; i  ) {
            Person per = new Person {
                Name = "Tim"
            };
            //same
            Console.WriteLine(per.GetHashCode());
        }
    }
      

    }

    открытый класс Student {имя открытой строки; }

    публичная структура Person { имя публичной строки; }

Комментарии:

1. Поскольку код с типом значения оптимизируется, а со ссылочным типом — нет, он работает по-разному с созданием экземпляра new Student() один раз и в теле цикла. Таким образом, существует разница между 1 экземпляром и 10 экземплярами. struct не по типу-ref, и он ведет себя так же, как int здесь.

Ответ №1:

Во-первых, позвольте мне указать на разницу между вашими методами:

Метод Calcu1 , Calcu4 , Calcu5 Calcu7 : переменная была объявлена снаружи и установлена внутри цикла. Значение будет присутствовать вне цикла.

Метод Calcu2 , Calcu3 , Calcu6 Calcu8 : Переменная была объявлена внутри цикла и не будет доступна снаружи.

Ваш хэш-код Calcu3 меняется, потому что вы создаете каждый раз другой объект. При создании Student через new стек будет иметь ссылку на новый объект в куче. Эта ссылка меняется каждый раз, потому что вы создаете 10 новых объектов.

Ваш хэш-код Calcu8 отличается, потому что это a struct , а структуры сохраняются в куче.

Смотрите здесь для получения дополнительной информации о stack an heap. На этой стороне вы также найдете определение того, что хранится в куче и в стеке.

В стеке:

«Вещи», объявленные в следующем списке объявлений типов, являются типами значений (поскольку они взяты из System.ValueType): bool, byte, char, decimal, double, enum, float, int, long, sbyte, short, struct, uint, ulong, ushort

В куче:

«Вещи», объявленные в следующем списке объявлений типов, являются ссылочными типами (и наследуются от System.Объект… за исключением, конечно, объекта, которым является System.Объект object): класс, интерфейс, делегат, объект, строка

Комментарии:

1. Большое спасибо, братан. Но у меня все еще есть пара вопросов. 1.Хэш-код Calcu8 в моем тесте тот же, а также подтверждается вашими словами «потому что это структура, а структуры сохраняются в куче». 2. Почему ValueType не может сохраняться в куче снова и снова в цикле for?

2. Типы значений могут быть размещены в стеке или куче. Ссылочные типы не могут быть выделены стеком.