Разница в инициализации статической переменной встроенной или в статическом конструкторе в C#

Я хотел бы знать, в чем разница между инициализацией статического члена в строке, как в:

class Foo
{
    private static Bar bar_ = new Bar();
}

или инициализируя его внутри статического конструктора, как в:

class Foo
{
    static Foo()
    {
        bar_ = new Bar();
    }
    private static Bar bar_;
}
Mehdi Khademloo 03.12.2016 02:58
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
18
1
11 843
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

В данном случае не думаю, что здесь есть какая-то практическая разница. Если вам нужна какая-то логика при инициализации статических переменных - например, если вы хотите использовать разные конкретные типы интерфейса при разных условиях, - вы должны использовать статический конструктор. Иначе в моей книге подойдет встроенная инициализация.

class Foo
{
    private static IBar _bar;

    static Foo()
    {
        if (something)
        {
            _bar = new BarA();
        }
        else
        {
            _bar = new BarB();
        }
    }
}

На самом деле, это может иметь большое практическое значение - см. Здесь (разница была «работает» против «не работает»): stackoverflow.com/questions/217932/…

Marc Gravell 20.10.2008 18:05

Я считаю описанную там ситуацию очень странной: | Подумав об этом, в своих синглтонах я всегда использую два статических объекта, реальный экземпляр и объект, который нужно заблокировать. Экземпляр, который я всегда создаю в методе свойств, объект блокировки, который я создаю встроенным. Я никогда не думал об этом раньше.

Torbjørn 20.10.2008 19:04

Тобьорн: Похоже, вы обычно выполняете блокировку, когда в этом нет необходимости :) (В большинстве случаев я считаю, что гарантии статической инициализации вполне подходят для синглтонов.)

Jon Skeet 20.10.2008 19:23

Наверное, это правильно. Но я считаю, что всегда лучше реализовать блокировку, чем однажды забыть о ней, когда она мне действительно нужна: |

Torbjørn 21.10.2008 10:34
Ответ принят как подходящий

Если у вас есть статический конструктор в вашем типе, он изменяет инициализацию типа из-за того, что флаг до поля больше не применяется.

Это также влияет на порядок инициализации - все инициализаторы переменных выполняются перед статическим конструктором.

Насколько я знаю, это все.

Конкретный пример того, почему это важно: stackoverflow.com/questions/217932/…

Marc Gravell 20.10.2008 18:06

По вашей ссылке: The runtime could decide to run the type initializer on loading the assembly to start with. Я предполагаю, что с универсальными классами (class Sample<T>) правила меняются? С разрешением во время компиляции (например, C++) правила будут такими же, но .NET выполняет разрешение во время выполнения. Среда выполнения не будет создавать экземпляры для всех возможных комбинаций, и я сомневаюсь, что при загрузке сборки она будет смотреть вперед, чтобы увидеть, какие типы используются.

Nelson Rothermel 08.11.2012 03:11

@NelsonRothermel: он инициализирует тип при первом использовании созданного типа - поэтому, если вы используете Foo<int>, он инициализирует его тогда, а затем снова запустит инициализатор типа, если вы используете Foo<string>.

Jon Skeet 08.11.2012 03:15

И есть предупреждение анализа кода, CA1810, которое рекомендует встроенную инициализацию для повышения производительности. «Статические проверки конструктора могут снизить производительность», - говорится в нем.

Şafak Gür 13.04.2013 11:58

Ответ сумеречной зоны: существует разница в порядок исполнения между встроенными инициализаторами и назначением ctor ... когда вы смешиваете экземпляры и статические члены и наследование для загрузки.

For static members, static initializers 
Static ctors (execute bottom up)
Base static initializer
Base static ctor and so on

For instance members, initializers in current class execute first
Then initializers in base class execute ( up the chain)
Then top-most base ctor is executed (and we walk down now. Instance ctors execute top-down)
Finally current type's ctor is executed.

Пример :)

public class CBase
    {
        static Talkative m_Baseob1 = new Talkative("Base Static Initializer-");
        static Talkative m_Baseob2;
        Talkative m_Baseob3 = new Talkative("Base Inst Initializer");
        Talkative m_Baseob4;
        static CBase()
        {
            Console.WriteLine("***MethodBegin: Static Base Ctor");
            m_Baseob2 = new Talkative("Base Static Ctor");
            Console.WriteLine("***MethodEnd: Static Base Ctor");
        }
        public CBase()
        {
            Console.WriteLine("***MethodBegin: Instance Base Ctor");
            m_Baseob4 = new Talkative("Base Instance Ctor");
            Console.WriteLine("***MethodEnd: Instance Base Ctor");
        }
    }
    public class CDerived : CBase
    {
        static Talkative m_ob1 = new Talkative("Derived Static Initializer");
        static Talkative m_ob2;
        Talkative m_ob3 = new Talkative("Derived Inst Initializer");
        Talkative m_ob4;
        static CDerived()
        {
            Console.WriteLine("***MethodBegin: Derived Static Ctor");
            m_ob2 = new Talkative("Derived Static Ctor");
            Console.WriteLine("***MethodEnd: Derived Static Ctor");
        }
        public CDerived()
        {
            Console.WriteLine("***MethodBegin: Derived Instance Ctor");
            m_ob4 = new Talkative("Derived Instance Ctor");
            Console.WriteLine("***MethodEnd: Derived Instance Ctor");
        }
    }
    internal class Talkative
    {
        public Talkative(string sID)
        {
            Console.WriteLine(sID + " - Talkative created" );
        }
    }

    # Main function somewhere
    CDerived s = new CDerived();

Выход:

Derived Static Initializer - Talkative created

***MethodBegin: Derived Static Ctor
Derived Static Ctor - Talkative created
***MethodEnd: Derived Static Ctor

Derived Inst Initializer - Talkative created

Base Static Initializer- - Talkative created

***MethodBegin: Static Base Ctor
Base Static Ctor - Talkative created
***MethodEnd: Static Base Ctor

Base Inst Initializer - Talkative created

***MethodBegin: Instance Base Ctor
Base Instance Ctor - Talkative created
***MethodEnd: Instance Base Ctor

***MethodBegin: Derived Instance Ctor
Derived Instance Ctor - Talkative created
***MethodEnd: Derived Instance Ctor 

Здесь статический конструктор CBase вызывается только потому, что создается экземпляр CDerived. Если вы просто вызываете метод в CDerived, которому не нужно касаться CBase, статический конструктор CBase вообще не будет вызван.

Jon Skeet 20.10.2008 19:22

Я был бы удивлен, если бы это было так ... Я упомянул наследование в первом предложении. Моя точка зрения: разница в том, как инициализируется переменная, в зависимости от того, как (инициализатор поля или в ctor), будь то static / inst и находится ли она в иерархии типов. но да .. Мой ответ - излишество для OP q;)

Gishu 20.10.2008 20:50

Другие вопросы по теме