Pergunta

namespace MyNameSpace
{
    static class MyClass
    {
        static MyClass()
        {
            //Authentication process.. User needs to enter password
        }

        public static void MyMethod()
        {
            //Depends on successful completion of constructor
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyClass.MyMethod();
        }
    }
}

Aqui está a sequência que assumi

  1. Início do construtor estático
  2. Fim do construtor estático
  3. Início do principal
  4. Início do meu método
  5. Fim do principal

Agora, em qualquer cenário, se 4 começar antes de 2, estou ferrado.É possível?

Foi útil?

Solução

Você fez apenas uma pergunta aqui, mas há cerca de uma dúzia de perguntas que você deveria ter feito, então responderei a todas.

Aqui está a sequência que assumi

  1. Início do construtor de classe (também conhecido como cctor)
  2. Fim do cctor
  3. início do principal
  4. início de MyMethod

Isso está correto?

Não. A sequência correta é:

  1. Início do cctor para programa, se houver. Não existe.
  2. Fim do cctor para o programa, se houver. Não existe.
  3. Início do principal
  4. Início do cctor para MyClass
  5. Fim do cctor para MyClass
  6. Início de MyClass.MyMethod

E se houver um inicializador de campo estático?

O CLR tem permissão para alterar a ordem em que os inicializadores de campo estático são executados em alguns casos. Veja a página de Jon sobre o assunto para detalhes:

As diferenças entre construtores estáticos e inicializadores de tipo

É possível que um método estático como MyMethod seja chamado antes que o cctor dessa classe seja concluído?

Sim. Se o próprio cctor chamar MyMethod, obviamente, MyMethod será chamado antes que o cctor seja concluído.

O cctor não chama MyMethod. É possível que um método estático como MyMethod seja chamado antes que o cctor de MyClass seja concluído?

Sim. Se o cctor usar outro tipo cujo cctor chama MyMethod, MyMethod será chamado antes que o cctor MyClass seja concluído.

Nenhum cctor chama MyMethod, direta ou indiretamente! Agora é possível para um método estático como MyMethod ser chamado antes que o cctor de MyClass seja concluído?

Não.

Isso ainda é verdade mesmo se houver vários tópicos envolvidos?

Sim. O cctor terminará em um thread antes que o método estático possa ser chamado em qualquer thread.

O cctor pode ser chamado mais de uma vez? Suponha que dois threads façam com que o cctor seja executado.

O cctor tem garantia de ser chamado no máximo uma vez, não importa quantos tópicos estejam envolvidos. Se dois threads chamam MyMethod "ao mesmo tempo", eles disparam. Um deles perde a corrida e bloqueia até que o cctor MyClass termine no tópico vencedor.

O segmento perdedor bloqueia até que o cctor termine? Sério ?

Sério.

E daí se o cctor no encadeamento vencedor chamar o código que bloqueia em um bloqueio anteriormente realizado pelo encadeamento perdedor ?

Então você tem uma condição clássica de inversão de ordem de bloqueio. Seu programa bloqueia. Para sempre.

Isso parece perigoso. Como posso evitar o impasse?

Se dói quando você faz isso, pare de fazer isso . Nunca faça algo que possa bloquear um cctor.

É uma boa ideia confiar na semântica de inicialização do cctor para impor requisitos de segurança complexos? E é uma boa ideia ter um cctor que interaja com o usuário?

Nem são boas ideias. Meu conselho é que você deve encontrar uma maneira diferente de garantir que as pré-condições que afetam a segurança de seus métodos sejam atendidas.

Outras dicas

De acordo com o MSDN , um construtor estático:

Um construtor estático é chamado automaticamente para inicializar a classe antes que a primeira instância seja criada ou qualquer membro estático seja referenciado.

Portanto, o construtor estático será chamado antes que o método estático MyClass.MyMethod() seja chamado (assumindo que não também chamado durante a construção estática ou inicialização de campo estático, é claro).

Agora, se você está fazendo algo assíncrono nesse static constructor, é seu trabalho sincronizá-lo.

O nº 3 é, na verdade, o nº 1: a inicialização estática não começa até o primeiro uso da classe à qual pertence.

É possível se MyMethod for chamado a partir do construtor estático ou de um bloco de inicialização estático.Se você não invocar MyMethod direta ou indiretamente de seu construtor estático, tudo bem.

Da documentação (ênfase minha):

Um construtor estático é chamado automaticamente para inicializar a classe antes que a primeira instância seja criada ou quaisquer membros estáticos sejam referenciado .

Você pode garantir que 4 sempre virá após 2 (se você não criar uma instância de sua classe a partir de seu método estático), no entanto, o mesmo não é verdade para 1 e 3.

O construtor estático será chamado antes de meu método ser executado.No entanto, se você está ferrado se 4 for chamado antes de 2, então sugiro que você repense seu design.Não deveria estar fazendo coisas complicadas em um construtor estático de qualquer maneira.

O CLR garante que o construtor estático seja executado antes que qualquer membro estático seja acessado.No entanto, seu design é um pouco malcheiroso.Seria mais simples fazer algo assim:

static void Main(string[] args) 
{ 
     bool userIsAuthenticated = MyClass.AuthenticateUser();
     if (userIsAuthenticated)
         MyClass.MyMethod(); 
 } 

Com o seu design, se a autenticação falhar, a única maneira de impedir a execução de MyMethod é lançando uma exceção.

É garantido que um construtor de classe estática foi chamado antes que qualquer um de seus métodos fosse executado.Exemplo:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Press enter");
        Console.ReadLine();
        Boop.SayHi();
        Boop.SayHi();
        Console.ReadLine();
    }

}

static class Boop
{
    static Boop()
    {
        Console.WriteLine("Hi incoming ...");
    }

    public static void SayHi()
    {
        Console.WriteLine("Hi there!");
    }
}

Resultado:

Pressione Enter

// depois de pressionar enter

Olá, entrando ...

Olá!

Olá!

Esta é a ordem real em que as coisas acontecem:

  1. Início do Main
  2. Início do construtor estático MyClass
  3. Fim do construtor estático MyClass
  4. Início do MyMethod
  5. Fim do Main

Ou você pode avançar no depurador.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top