Pergunta sobre static, c# – Por que o C # não suporta variáveis ​​estáticas locais como o C faz?

58

Por que o C # não tem variáveis ​​estáticas locais como C? Eu sinto falta disso!!

Eu sei o que C # estático significa ... minha pergunta é usando estática no sentido C JoelFan
@Atomosk Qualquer lugar onde você deseja que o valor seja o mesmo a cada vez que a função é carregada, sem ter que expor a classe completa. AustinWBryan
Você teria que perguntar aos designers. John Saunders
Como outros já disseram, isso tem a ver com o estado em que o estado deveria viver e, na maioria das vezes, eu concordo. Mas se você quiser uma solução de como fazer isso, eu postei uma classe genérica para imitar a funcionalidade aquistackoverflow.com/a/17817240/2611613 Iddillian

Sua resposta

12   a resposta
0

o. Como o C # está limitando o escopo das variáveis ​​estáticas às classes, você pode usar a classe aninhada como um escopo.

Por exemplo:

<code>public class Foo {
    public int Increment() {
        return IncrementInternal.Increment();
    }

    private static class IncrementInternal {
        private static int counter = 0;
        public static int Increment() {
            return counter++;
        }
    }
}
</code>

AquiFoo suportaIncrement método, mas o seu apoio pela classe aninhada privadaIncrementInternal que contém a variável estática como um membro. E claro,counter não é visível no contexto (outros métodos) deFoo.

BTW, se você quiser acessarFoo contexto (outros membros e métodos) dentroIncrementInternal.Incrementvocê pode passarthis como um parâmetro paraIncrementInternal.Increment quando você liga deFoo.

Para manter o escopo o menor possível, sugiro criar uma classe aninhada por cada método. E como provavelmente não é tão comum, o número de classes aninhadas permanecerá pequeno o suficiente para mantê-lo.

Eu acho que é mais limpo que funções anônimas ou IIFE.

Você pode ver uma demonstração ao vivoAqui.

1

se usado apenas nesse método. No entanto, um membro estático de nível de método seria mais encapsulado. Se os dados armazenados em um membro forem usados ​​somente por um único método, eles só devem ser acessíveis por esse método único.

No entanto, você pode conseguir quase exatamente o mesmo efeito em C #, criando uma classe aninhada.

A classe aninhada tem acesso às variáveis ​​privadas da classe aninhada. Em seguida, você pode tornar a variável private e colocar o método one nela, mas ainda precisará enviar a instância da classe aninhada. Claro, você pode fazer uma extensão de classe. Então ninguém seria o mais sábio. Lee Louviere
111

e deixaram de fora um recurso útil para se adequarem.

Todos os argumentos sobre como você deve codificar, e o que é inteligente, e você deveria reconsiderar seu modo de vida, são desculpas defensivas pomposas.

Claro, C # é puro e orientado para o whatchamacallit. É por isso que eles geram automaticamente locais persistentes para funções lambda. Tudo é tão complicado. Eu me sinto tão idiota.

O escopo do loop estático é útil e importante em muitos casos.

Resposta curta e real, é preciso mover a estática local para o escopo da classe e viver com a poluição do namespace da classe em C #. Leve sua reclamação para a prefeitura.

Esta resposta é reiterada pelas respostas ridículas a ela. por exemplo, "As previsões de que nenhum código fora de uma função em particular precisará acessar uma variável estática em particular estão erradas" - 1) tais "previsões" virtualmente nunca estão erradas, 2) ninguém está fazendo nenhuma previsão e 3) se surgir uma necessidade de acessar uma função local estática, ela pode ser movida para torná-la estática de classe. E "o que quer que você faça, não vai contornar o fato de que agora você tem um campo de instância associado à instância da classe" - as variáveis ​​estáticas não estão vinculadas a instâncias. Jim Balter
As previsões de que nenhum código fora de uma função específica precisará acessar uma determinada variável estática estão, com freqüência, erradas. Se não fosse pela sobrecarga do método, talvez seja possível adicionar um método para decorar sua declaração de variável estática de modo a permitir que outros métodos se refiram a uma de suas variáveis ​​como algo comomethodName.variableName, mas a presença de sobrecarga torna muito mais difícil identificar de forma clara uma variável que é local para um método específico. supercat
Na verdade, o VB.NET apenas cria variáveis ​​de nível de classe estáticas nos bastidores. Variáveis ​​de método estático não são suportadas pelo CLR. JDB
@JDB Bem, a mesma coisa acontece em C ++ :) O que quer que você faça, você não vai se livrar do fato de que agora você está tendo um campo de instância associado à instância dada da classe. É (moderadamente útil) conveniência do compilador, mas não uma funcionalidade separada. Qualquer coisa que você possa fazer com variáveis ​​locais estáticas, você também pode fazer com campos de instância (ou campos estáticos). Luaan
0

todo é compartilhado entre todas as instâncias.

Eu tive que me corrigir e a outros programadores que esperam que seja único por instância de classe usando o método.

No entanto, se você tornar uma classe estática ou estática de uma classe, ficará sintaticamente claro se há uma instância por classe de contêiner ou uma instância.

Se você não usá-los, fica mais fácil refatorar mais tarde também.

Lee: Normalmente, porque você está lidando com a reentrada ou algum outro problema similar ao método específico. Nesses casos, logicamente faz mais sentido associar o estado ao método do que à classe inteira, mesmo que não exista uma diferença embasada na maneira como é implementada pelo CLR versus uma variável estática privada normal. reirab
Nos poucos casos em que você precisa armazenar uma variável somente dentro de um método, você deve estar se perguntando por que você dispersou informações de estado de classe compartilhada por meio de vários métodos. Lee Louviere
Eu acho que a palavra "estática" deve deixar claro que existe apenas uma variável JoelFan
29

objeto ou parte de umtipo, não faz parte de um método. (A exceção sendo variáveis ​​capturadas, é claro).

Se você quiser o equivalente a uma variável estática local, crie uma variável de instância ou uma variável estática - e considere se o método em si deve realmente fazer parte de um tipo diferente com esse estado.

@ Jon, eu pensei muito sobre isso e sim eu também li um comentário seu sobreblogs.msdn.com/b/csharpfaq/archive/2004/05/11/… e no geral agora sinto que faz mais sentido. Obrigado. Dinesh
@ Ken: Ah, se você não está falando sobre o estado mutável, eu acho que é um problema diferente - ou pelo menos é apenasparte do que uma variável estática em C faz. Você pode usarconst para variáveis ​​locais em C #, claro, embora não seja a mesma coisa também ... Jon Skeet
@ DnshPly9: Não sei bem como explicar melhor, para ser honesto. Que pedaço você não entende? Jon Skeet
@JimBalter: Acho que teremos que concordar em discordar. (Embora euFaz Concordamos que o escopo limitado das estáticas de nível de método é um benefício.) Jon Skeet
0

do campos estáticos públicos para a classe. Muito pouca mudança lógica, não acha?

Se você acha que seria uma grande mudança lógica, eu estaria interessado em saber como.

<code>class MyClass
{
    public static float MaxDepthInches = 3;

    private void PickNose()
    {
        if (CurrentFingerDepth < MyClass.MaxDepthInches)
        {
            CurrentFingerDepth++;
        }
    }
}
</code>
Aqui estão duas grandes mudanças lógicas: 1) É público e pode, portanto, ser modificado por código fora da classe. Isso significa que outras pessoas que usam sua classe podem modificá-la de maneiras imprevisíveis para o seu código. Escusado será dizer que isso geralmente é ruim. 2) O escopo da variável é toda a classe e não apenas o método. Alterar o escopo de um método para a classe inteira é uma grande mudança, mesmo se você declará-lo como privado. reirab
7

ns! Você deu outro passo para se tornar umreal programador.

Não ouça todas as pessoas dizendo que locais estáticos não são "limpos", que impedem a "legibilidade" e podem levar a "bugs" sutis e difíceis de encontrar. Absurdo! Eles apenas dizem isso porque sãowannabe programadores! Muitos deles provavelmente estão brincando com uma linguagem de programação funcional esotérica durante o tempo livre. Você acredita nisso? Que bando de descolados!

Real programadores abraçam um paradigma que eu gosto de chamarSDD - Sefeito ideDdilaceradoDesign. Aqui estão algumas das leis mais importantes:

Não seja previsível! Nunca retorne a mesma coisa de um método duas vezes - mesmo que esteja sendo chamado com os mesmos argumentos!

Parafuso pureza - vamos sujar! Estado, por natureza, anseia por mudar, porque é ummonóide insaciável na categoria de endofonitores poliamorosos, ou seja, gosta de ser tocado por tantos colaboradores quanto possível. Nunca perca a oportunidade de fazer o favor!

Entre as ferramentas usadas para codificar de uma maneira dirigida pelos efeitos colaterais estão, obviamente, variáveis ​​locais estáticas. No entanto, como você percebeu, o C # não os suporta. Por quê? Porque nas últimas duas décadasMicrosoft foi infiltrada pelos chamadosCodificadores Limpos que favorecem a manutenção da flexibilidade e controle. Você consegue se lembrar da última vez que viu nossa amada tela azul? Agora adivinhe de quem é a culpa!

Mas não tenha medo!Real os desenvolvedores não precisam sofrer com essas decisões ruins de design. Como foi mencionado antes, é possível ter variáveis ​​locais que são estáticas com a ajuda de lambdas.

No entanto, a solução fornecida não foi satisfatória. Usando oresposta anterior nosso código quase compatível com SDD seria algo como isto:

<code>var inc = Increment();
var zero = inc();
var one = inc();
</code>

ou

<code>var zero = Increment()();
</code>

Mas isso é bobagem. Até mesmo umwannabe desenvolvedor pode ver queIncrement() não é um método normal e será suspeito. UMAreal programador, por outro lado, pode torná-lo ainda mais parecido com o SDD. Ele ou ela sabe que podemos fazer uma propriedade ou campo parecer um método, dando-lhe o tipoFunc<T>! Nós apenas temos que inicializá-lo executando um lambda que, por sua vez, inicializa o contador e retorna outro lambda incrementando o contador capturado!

Aqui está no código SDD adequado:

<code>public Func<int> Increment = new Func<Func<int>>(() =>
{
    var num = 0;
    return () => num++;
}).Invoke();
</code>

(Você acha que o acima parece um tipoIIFE? Sim, você está certo e deveria se envergonhar.)

Agora toda vez que você ligarIncrement() ele retornará algo diferente:

<code>var zero = Increment();
var one = Increment();
</code>

Claro que você também pode fazer isso para que ocontador sobrevive a vida útil da sua instância.

Isso vai mostrar pra eleswannabe programadores!

@ GoodNightNerdPride Eu resolvi isso usando um bacanaFunc<,> técnica! Isso é tão legal :) Ao fornecer um nãonull variável, ele armazena. Ao fornecernull, isso recupera! silkfire
@GoodNightNerdPride Bifurcou seu violino:dotnetfiddle.net/eEXkSi silkfire
Variáveis ​​locais estáticas não são apenas para estados modificáveis. Algo que eu corro muito é algo assim:GetFooByID(int id) que retorna umFoo objeto pesquisando em uma matriz estática ou dicionário que é inicializado uma vez e nunca modificado. Ter o array / dicionário no nível do método faz mais sentido do que o nível de classe. Mr Anderson
Claro que sim, mas você meio que perdeu o meu ponto. Rapaz, espero que você não esteja tentando usar isso em um projeto sério de software. Também o propósito do lambda acima écapturar a variável local, o que implica que só deve ser alterado pelo lambda e mais ninguém. É provavelmente por isso que o compilador C # se recusa a capturarref tipos como uma medida de segurança. Good Night Nerd Pride
15

mas acredito que você pode realizar tudo o que puder com uma estática local, usando uma estática de nível de classe que é usada apenas para um método. Obviamente, isso vem com alguma alteração sintática, mas acredito que você pode obter qualquer funcionalidade que precisar.

Além disso, Eric Lippert responde a perguntas como esta em seublog muito. Geralmente respondido emdeste jeito: "Me perguntam" por que o C # não implementa o recurso X? "O tempo todo. A resposta é sempre a mesma: porque ninguém jamais projetou, especificou, implementou, testou, documentou e enviou esse recurso." Essencialmente, suas respostas geralmente se resumem a: custa dinheiro adicionar qualquer recurso e, portanto, muitos recursos em potencial não são implementados porque não saíram do lado positivo da análise de custo-benefício.

Eu não poderia ter dito melhor de mim mesmo. Eric Lippert
Eu posso respeitar a segunda parte desta resposta. A primeira parte é uma solução, mas não uma desculpa. Essa é a parte importante para ver aqui. Como outros já disseram, "você pode realizar X fazendo Y" não é diferente de "você pode simular todos os recursos de qualquer linguagem de programação com uma máquina". E, no entanto, não fazemos isso porque, apesar de ser uma "ferramenta suficientemente poderosa", uma linguagem que só tem as mesmas funções de uma máquina de turing (além da memória infinita, é claro) é que ela não é produtiva o suficiente. Gurgadurgen
Eu acredito que você pode realizar tudo que você poderia com uma estática local, usando uma estática de nível de classe que é usada apenas para um método. -- espantalho. Todo mundo sabe disso, mas é completamente irrelevante porque não abordaporque as pessoas querem a estatística local e do método - a localidade lexical é um princípio importante e muitos linters a forçam. O segundo parágrafo é comovirtus dormitiva oule meilleur des mondes possibles - Handwaves genéricos que não abordam a questão. (C # felizmente adicionou muitas boas características desde que EL deixou a equipe.) Jim Balter
O problema com a implementação de uma estática local com uma classe estática é o espaço de nome de classe é poluído desnecessariamente. O problema dos requisitos de recursos para adicionar recursos ao C # é o motivo pelo qual a maioria dos idiomas da Microsoft (e outros, tosse, Sun / Oracle) não são fantásticos. Eles, sem remorso, fazem o que é "bom o suficiente", não o que é bom. demented hedgehog
1

riáveis ​​fora do escopo de uma classe ou método local. Variáveis ​​dentro de um método não podem ser declaradas estáticas, como você pode estar acostumado a fazer em C. Entretanto, você sempre pode usar uma variável estática de classe como um substituto.

Como uma prática geral, geralmente há maneiras de resolver problemas de programação em C # sem recorrer ao uso de estática em nível de método. Estado é geralmente algo que você deve projetar em classes e tipos, não métodos.

-3

xemplo:

<code>public Func<int> Increment()
{
    int num = 0;
    return new Func<int>(() =>
    {
        return num++;
    });
}
</code>

Você pode ligar assim:

<code> Func<int> inc = Increment();
 inc();
</code>
A resposta aceita tem pontuação -3. WTH? cp.engr
Muito JavaScript JoelFan
Outra resposta foi postada há um ano e meio com essa mesma abordagem geral. Servy
Não, esta resposta faz algum sentido, exceto que deve ser estático. Por que não adicionar uma estática privada que você diz, mas essa é realmente a questão em questão, por que não há estática local. Obviamente, a resposta é apenas o que você sugere, por que não usar uma classe local estática em vez disso? Agora estamos na questão real que é estática de classe vs static local que é melhor, bem o contexto necessário para a estática local não é um super simples. RJ Thompson
Isso não resolve nada. Cada vez que você chama o método, você obtém um novoIncrement função, comnum = 0. Se você mudar oIncrement método para estática, porque não basta usarprivate static num = 0; ? Você não ganha nada com isso. Rob
-3

rth anunciandoBOAS NOTÍCIAS, PESSOAL!, C # 6.0 permite que ousing static declaração. Isso efetivamente permite que você importe métodos de classe estática (e, ao que parece, propriedades e membros também) para o escopo global.

Em resumo, você pode fazer algo assim:

<code>using NUnit.Framework;
using static Fizz.Buzz;

class Program
{
    [Test]
    public void Main()
    {
        Method();
        int z = Z;
        object y = Y;
        Y = new object();
    }
}


namespace Fizz
{
    class Buzz
    {
        public static void Method()
        {
        }

        public static int Z;

        public static object Y { get; set; }
    }
}   
</code>

Embora isso esteja disponível apenas no C # 6.0, pelo que entendi, os assemblies gerados devem ser compatíveis com as plataformas .NET anteriores (corrija-me se estiver errado).

Isso não é relevante para a questão. JoelFan
27

Por que o C # não suporta variáveis ​​de método estático? lida com a pergunta exata feita na postagem original:

Existem dois motivos para o C # não ter esse recurso.

Primeiro, é possível obter quase o mesmo efeito tendo uma estática de nível de classe, e a adição de estatísticas estáticas exigiria maior complexidade.

Segundo, as estáticas de nível de método são um pouco notórias por causar problemas quando o código é chamado repetidamente ou a partir de vários encadeamentos, e como as definições estão nos métodos, é mais difícil encontrar as definições.

[Autor:Eric Gunnerson]

Eu entendo que isso não é necessariamente a sua opinião, mas pode-se fazer exatamente o mesmo argumento para estática de nível de classe. "Multithreading é difícil e bugprone" e "múltiplos usuários modificando o mesmo valor estático na memória é mais bugprone e difícil de controlar" não é desculpa para não incluir um recurso. Esses são problemas com o conjunto de recursos existente que não são particularmente exacerbados por esse recurso. Eles têm classes estáticas e construtores estáticos pelo amor de Deus, que são ainda mais conhecidos por serem difíceis de rastrear e ainda mais difícil de fazer com testes de unidade! Gurgadurgen

Perguntas relacionadas