4

Inspired by JavaScript Closures I tried to Simulate Local static variables in C# using Func<> Delegate... Here is my code..

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

Func<int> inc = Increment();
Console.WriteLine(inc());//Prints 1
Console.WriteLine(inc());//Prints 2
Console.WriteLine(inc());//Prints 3

I am eager to know if there is any other way of simulating local static variable in C#? Thank You.

Mark Sowul
  • 10,244
  • 1
  • 45
  • 51
Uthaiah
  • 1,283
  • 13
  • 14
  • 3
    Where is the static variable ? – nraina Jul 15 '14 at 14:12
  • 1
    @Arjuna: I assume they are referring to `num` which becomes part of the closure and cannot otherwise be accessed – Matt Burland Jul 15 '14 at 14:13
  • 8
    The C# way to make a static variable would be to actually create a class with a `static` member. This feels like you are asking "how can I make C# behave like Javascript?" which I think the answer should be "don't". They are two different languages and forcing one to act like the other will only end in tears. – Matt Burland Jul 15 '14 at 14:14
  • 1
    I have simulated it.. there is no static keyword there.. but if you call the function and invoke the FUNC<> delegate the value for 'num' is retained. – Uthaiah Jul 15 '14 at 14:14
  • how many times invoked ?? – BRAHIM Kamel Jul 15 '14 at 14:18
  • 2
    Could you be more precise what you mean by "simulate static variable"? What are the **exact** conditions you would need to say you have simulated a static variable? – Ben Aaronson Jul 15 '14 at 14:18
  • The num variable acts like a static variable. – Uthaiah Jul 15 '14 at 14:21
  • 4
    @Uthaiah in what way does it act like a `static` variable? `static` variables belong to the *class*, this belongs to the instance. This is definitely **not** the equivalent to a `static` variable. – James Jul 15 '14 at 14:22
  • In what way? I don't understand how the code snippet you posted makes `num` "act like a static variable". – Ben Aaronson Jul 15 '14 at 14:22
  • in c# a static variable would simply be `static int num = 0`, what are you trying to achieve? – Sayse Jul 15 '14 at 14:23
  • 1
    I meant static variables like C and C++.. I know C# doesnt support ststic local vriable. so i tried to implement it like this in C# – Uthaiah Jul 15 '14 at 14:24
  • 1
    C# has instance variables, their scope is local to its class.. – Sayse Jul 15 '14 at 14:27
  • 5
    Right, but he's trying to emulate *function-scoped static variables*, like you find in C++ - `function() { static int = 0; .. }` – antiduh Jul 15 '14 at 14:27
  • 4
    Okay, I actually understand what's being asked now. For others who are confused, see http://stackoverflow.com/questions/1049689/why-doesnt-c-sharp-support-local-static-variables-like-c-does and AlfredBr's answer – Ben Aaronson Jul 15 '14 at 14:28
  • Right ok, thanks Ben.. I am still yet to find a reason to even need one in C# though, thread safe I suppose? – Sayse Jul 15 '14 at 14:29
  • @Sayse Basically, it's about limiting the scope. This is helpful to prevent access from methods that shouldn't touch that variable. Not that I have a *practical* scenario for their usage, but they're analogous to private fields, except that they're "private" in the function, not the whole class. – Luaan Jul 15 '14 at 14:33
  • you may create a class with a method for retrieving the incremented value. if you say static it is not local, and if it is local it cant be static. so define your scope for the increment i.e. method, class or application level then go for the implementation. – pushpraj Jul 15 '14 at 14:33
  • 2
    @Luaan - Thanks, this question still screams [xy problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) to me though – Sayse Jul 15 '14 at 14:35
  • Sorry for bad english :( @antiduh thanks for making it clear what i wanted to explain.. – Uthaiah Jul 15 '14 at 14:37
  • 1
    The question misses an important part : `var f = Increment(); while(true) Console.WriteLine(f.Invoke());` – Larry Jul 15 '14 at 14:38
  • 4
    I wouldn't consider this a duplicate of that other question, it asks for something different and the potential answers are different. – Ben Aaronson Jul 15 '14 at 14:40
  • 1
    @BenAaronsonm It ask for how to do something, the other answer is explaining why it's not possible to do that thing. It answers this question by stating that it's not possible. – Servy Jul 15 '14 at 14:45
  • Whenever I need static variables that can be used globally, I simply create a static class and utilize static properties to get them, and in this case, increment it as well. public static class Static { private static int _myInt = 0; public static int Increment { get { return ++_myInt; } } } – Cory Jul 15 '14 at 14:46
  • 1
    @KoBE The goal here is to *reduce* the scope in which the variable is a valid identifier to as small a scope as possible. That's increasing the scope to a *much* greater scope than it is needed in. – Servy Jul 15 '14 at 14:47
  • @Servy Surely this question is asking how to work around the limitation that static local variables aren't allowed, not asking how to do static local variables. – Ben Aaronson Jul 15 '14 at 14:53
  • @Servy Ah, I misunderstood that part. You could still reduce the scope by creating the class within the current class' scope. Still, not an optimal solution. – Cory Jul 15 '14 at 14:54

1 Answers1

5

This is absolutely horrible, but one way would be to use an iterator method and discard the output. For example, if you wanted:

public void PrintNextNumber()
{
    static int i = 0; //Can't do this in C#
    Console.Out.WriteLine(i++);
}

You could instead write:

public IEnumerator<object> PrintNextNumber()
{
    int i = 0;
    while (true)
    {
        Console.Out.WriteLine(i++);
        yield return null;
    }
}

Then instead of calling PrintNextNumber(), you'd do var printNext = PrintNextNumber(); printNext.MoveNext;.

I really only wrote this answer for satisfying curiousity, I absolutely would not recommend really doing this!

It becomes even more nasty if you want to actually return something from the method but it's possible- you can yield return instead, then retrieve it using Current after having called MoveNext

Ben Aaronson
  • 6,955
  • 2
  • 23
  • 38
  • 1
    That doesn't make the value `static`. `PrintNextNumber().MoveNext` will *always* print out `0`, because a new enumerator is created each time you call `PrintNextNumber`. The only way to actually get the desired behavior would be to store the enumerator in a static variable so that the public method can return it or get it's next value, which is of course failing the requirement of not having a static field. – Servy Jul 15 '14 at 14:43
  • Nice one @BenAaronson :) – Uthaiah Jul 15 '14 at 14:49
  • @Servy The aim of not having a static field isn't because the OP has an aversion to the `static` keyword, it's to avoid having to expose the variable to a larger scope than it should be in. So having a static member field referring to the method doesn't have the same issue. – Ben Aaronson Jul 15 '14 at 14:49