Почему в C # порядок имеет значение для статической инициализации? - PullRequest
8 голосов
/ 19 марта 2009

Этот код имеет четко определенное поведение в C #, не работает:

class Foo
{
    static List<int> to = new List<int>( from ); // from is still null
    static IEnumerable<int> from = Something();
}

Примечание: я не спрашиваю, как исправить этот код, как Я уже знал, как это сделать

Чем это оправдано? C # уже проверяет время выполнения, чтобы обнаружить первый доступ к статическим членам. Почему бы не распространить это на вещи для каждого члена и запустить их по требованию или, что еще лучше, компилятор определит порядок во время компиляции?

Кстати: я думаю, что тот же вопрос (или почти тот же самый) также имеет место для нестатических членов.

Ответы [ 4 ]

12 голосов
/ 19 марта 2009

Инициализаторы - это просто синтаксический сахар. Компилятор помещает этот код в .cctor при компиляции вашего класса и помещает их в порядке их размещения в коде.

Он не запускает никаких проверок, потому что это не имеет смысла. У вас все еще могут быть циклы инициализации, так что в любом случае это не сработает.

Я писал об этом некоторое время назад, если вам интересно:

6 голосов
/ 19 марта 2009

Я могу представить программиста в зависимости от порядка инициализации из-за побочных эффектов с другими статическими классами. Мы оба знаем, что в зависимости от побочных эффектов это плохая практика, но это не обязательно незаконно.

Рассмотрим что-то вроде этого:

class Foo
{
    static string header = Bar.GetHeader();
    static string version = Bar.GetVersion();
}

И Bar.GetVersion предполагает, что Bar.GetHeader был вызван. Если бы компилятор мог изменить порядок инициализации, программист не смог бы гарантировать порядок инициализации.

Гадкий, само собой разумеющийся, но совершенно законный. Если вы представляете эффекты второго порядка (то есть вызываемые статические методы, которые сами зависят от классов, имеющих побочные эффекты), вы видите, что компилятор не может надежно переставить что-либо, как невозможно (в общем случае) компилятору переставить порядок вызовов функций в вашем статическом конструкторе.

1 голос
/ 19 марта 2009

C # выполняет проверки во время выполнения для обнаружения первого доступа к классу, но не переупорядочивает статическую инициализацию внутри класса.

Статические поля инициализируются сверху вниз, а затем статические конструкторы сверху вниз. Либо измените порядок ваших полей, либо создайте статический конструктор и инициализируйте поля из них.

См. Инициализаторы переменных в спецификации C # или эта статья об инициализаторах. Также вопрос Порядок статических конструкторов / инициализаторов в C # связан с этим.

1 голос
/ 19 марта 2009

Я думаю, что вам нужно использовать статический конструктор.

Вот так

class Foo
{
    static List<int> to;
    static IEnumerable<int> from;

    static Foo()
    {
        from = Something();
        to = new List<int>(from);
    }
}

Что касается того, почему C # не делает этого при первом доступе, я просто не вижу необходимости в такой сложности, когда есть другие альтернативы, которые проясняют, что происходит.

...