Подтвердить что ты не робот

Почему С# не поддерживает локальные статические переменные, такие как C?

Почему С# не имеет локальных статических переменных, таких как C? Я скучаю по этому поводу.

4b9b3361

Ответ 1

Вы можете имитировать его с помощью делегата... Вот мой пример кода:

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

Вы можете называть это следующим образом:

 Func<int> inc = Increment();
 inc();

Ответ 2

Потому что они прищурились и оставили полезную функцию, чтобы удовлетворить себя.

Все аргументы о том, как вы должны кодировать, и что умные, и вы должны пересмотреть свой образ жизни, - это напыщенные защитные оправдания.

Конечно, С# является чистым, а whatchamacallit-ориентированным. Вот почему они автоматически генерируют постоянные локали для лямбда-функций. Все это так сложно. Я чувствую себя таким глупым.

Статическая область цикла является полезной и важной во многих случаях.

Короткий, реальный ответ: вам нужно переместить локальную статику в область класса и жить с загрязнением пространства имен классов в С#. Возьмите жалобу в мэрию.

Ответ 3

Состояние обычно является частью объекта или части типа, а не части метода. (Исключение составляют захваченные переменные, конечно.)

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

Ответ 4

Запись в блоге MSDN Почему С# не поддерживает переменные статических методов? рассматривает точный вопрос, заданный в исходном сообщении:

Есть две причины, по которым С# не имеет этой функции.

Во-первых, можно получить почти такой же эффект, статический статический класс и добавление метода статики потребует увеличения сложность.

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

[Автор: Эрик Гуннерсон

Ответ 5

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

Кроме того, Эрик Липперт часто отвечает на такие вопросы blog. В общем, ответ в таким образом: "Меня спрашивают, почему С# не реализует функцию X?" Все время. Ответ всегда один и тот же: потому что никто никогда не разрабатывал, не определял, не реализовывал, не тестировал, не документировал и не отправлял эту функцию ". По сути, его ответы, как правило, сводятся к тому, что затраты на добавление какой-либо функции стоят денег, и поэтому многие потенциальные возможности не реализованы, потому что они не выходят на положительную сторону анализа рентабельности.

Ответ 6

Итак, вы хотите использовать статическую локальную переменную в своем методе? Поздравления! Вы сделали еще один шаг к тому, чтобы стать настоящим программистом.

Не слушайте всех людей, говорящих вам, что статические локальные жители не являются "чистыми", что они препятствуют "удобочитаемости" и могут привести к тонким и труднодоступным "ошибкам". Бред какой то! Они просто говорят, что они программисты-подражатели! Многие из них, вероятно, даже занимаются сексом с эзотерическим функциональным языком программирования во время их свободного времени. Ты можешь в это поверить? Какая кучка хипстеров!

Настоящие программисты используют парадигму, которую мне нравится называть SDD - S ide effect D riven D. Вот некоторые из наиболее важных законов:

Не предсказуем! Никогда не возвращайте одну и ту же вещь из метода дважды - даже если он вызывается с точно такими же аргументами!

Черновая чистота - пусть становится грязной! Состояние, по своей природе, жаждет перемен, потому что это ненасытный моноид предыдущий ответ, наш почти-SDD-совместимый код выглядел бы примерно так:

var inc = Increment();
var zero = inc();
var one = inc();

или

var zero = Increment()();

Но это просто глупо. Даже разработчик wannabe может видеть, что Increment() не является обычным методом и будет подозрительным. С другой стороны, реальный программист может сделать его еще более похожим на SDD. Он или она знает, что мы можем сделать свойство или поле похожим на метод, присвоив ему тип Func<T>! Мы просто должны инициализировать его, выполнив лямбду, которая, в свою очередь, инициализирует счетчик и возвращает еще один лямбда, увеличивающий захваченный счетчик!

Здесь он находится в правильном коде SDD:

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

(Вы думаете, что вышеупомянутый вид выглядит как IIFE? Да, вы правы, и вам должно быть стыдно за себя.)

Теперь каждый раз, когда вы вызываете Increment() он возвращает что-то другое:

var zero = Increment();
var one = Increment();

Конечно, вы также можете сделать так, чтобы счетчик выжил при жизни вашего экземпляра.

Это покажет им программистов wannabe!

Ответ 7

С# является компонентно-ориентированным языком и не имеет понятия переменных, выходящих за рамки класса или локального метода. Переменные внутри метода также не могут быть объявлены как статические, как вы привыкли делать в C. Однако вы всегда можете использовать статическую переменную класса в качестве замены.

Как правило, обычно существуют способы решения проблем программирования на С#, не прибегая к использованию статики уровня метода. Состояние - это то, что вы должны проектировать в классы и типы, а не методы.

Ответ 8

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

Однако вы можете достичь почти точно такого же эффекта в С#, создав вложенный класс.

Ответ 9

Я думаю, что идею локальной статики так же легко решить, создав публичные статические поля для класса. Как вы думаете, мало ли логических изменений?

Если вы считаете, что это будет большое логическое изменение, мне было бы интересно услышать, как это сделать.

class MyClass
{
    public static float MaxDepthInches = 3;

    private void PickNose()
    {
        if (CurrentFingerDepth < MyClass.MaxDepthInches)
        {
            CurrentFingerDepth++;
        }
    }
}

Ответ 10

Поскольку статические локальные переменные привязаны к методу, а метод используется для всех экземпляров.

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

Однако, если вы сделаете его статическим классом или статическим экземпляром класса, он синтаксически очистит, есть ли экземпляр для класса контейнера или один экземпляр вообще.

Если вы не используете их, становится легче реорганизовать и позже.

Ответ 11

Вы можете использовать вложенный класс в качестве обходного пути для этого. Поскольку С# ограничивает область действия статических переменных классами, вы можете использовать nested-class в качестве области действия.

Например:

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

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

Здесь Foo поддерживает метод Increment, но поддерживает его закрытым вложенным классом IncrementInternal который содержит статическую переменную в качестве члена. И, конечно, counter не виден в контексте (других методов) Foo.

Кстати, если вы хотите получить доступ к контексту Foo (другим членам и методам) внутри IncrementInternal.Increment, вы можете передать this в качестве параметра в IncrementInternal.Increment при вызове его из Foo.

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

Я думаю, что это чище, чем анонимные функции или IIFE.

Вы можете увидеть живое демо здесь.

Ответ 12

 using System;
 using System.Collections;

public class Program
{
    delegate bool DoWork();

   public static void Main()
   {
       DoWork work = Foo().GetEnumerator().MoveNext;

        work();
        work();
        work();         
   }

    public static IEnumerable Foo()
    {
        int static_x = 10;
        /*
       do some other static stuff....
        */

      main:

      //repetative housework
      Console.WriteLine(static_x);
      static_x++;


      yield return true;
      goto main;
  }


 }

Ответ 13

Если вы можете представить какой-то гибридный объект Lippert/Farnsworth, объявляющий ХОРОШИЕ НОВОСТИ КАЖДЫЙ!, С# 6.0 допускает оператор using static. Это эффективно позволяет вам импортировать статические методы класса (и, по-видимому, свойства и члены) в глобальную область.

Короче говоря, вы можете сделать что-то вроде этого:

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; }
    }
}   

Пока это доступно только в С# 6.0, из того, что я понимаю, сгенерированные сборки должны быть совместимы с предыдущими платформами .NET(исправьте меня, если я ошибаюсь).