tags:

views:

114

answers:

4

In VB6 there are local static variables that keep their values after the exit of procedure. It's like using public vars but on local block. For example:

sub count()
static x as integer
x = x + 1
end sub

After 10 calls, x will be 10. I tried to search the same thing in .NET (and even Java) but there was none. Why? Does it break the OOP model in some way, and is there a way to emulate that.

+6  A: 

The closest you can get is a static field outside the method:

private static int x;
public [static] void Foo() {
    x++;
}

Closure example as requested:

using System;
class Program {
    private static readonly Action incrementCount;
    private static readonly Func<int> getCount;
    static Program() {
        int x = 0;
        incrementCount = () => x++;
        getCount = () => x;
    }
    public void Foo() {
        incrementCount();
        incrementCount();
        Console.WriteLine(getCount());
    }
    static void Main() {
        // show it working from an instance
        new Program().Foo();
    }
}
Marc Gravell
Using the static constructor to initialize a delegate field with a closure is probably slightly closer in terms of access to the variable (unlike the static field, it won't be seen via reflection on the class or visible to other class methods)
Ben Voigt
@Ben - interesting approach, but lots of extra complexity - getting people to understand captured variables is tricky at the best of times ;-p
Marc Gravell
OK, I get it, but *why*? Does it break OOP in some way?
blez
@Marc: I agree that the simple static variable is the best trade-off of behavior and complexity. The use of a closure to create a variable with limited scope but unlimited lifetime is somewhat more common in certain functional languages which don't directly provide private fields -- a closure in the class factory does the trick.
Ben Voigt
Could you give me example of that?
blez
@blez - added example
Marc Gravell
A: 

You can always use static variables in a class for that purpose:

class C
{
  static int x=0;

  void count()
  {
    ++x; // this x gets incremented as you want 
  }
}
Blindy
A: 

I remember static private in visual basic. They were cool for some specific task.

No such thing in .net. You will have to stick with static outside the metod.

Daniel Dolz
There were some cool things in VB6 indeed.
blez
Well, they are available in VB.NET (though not C#)... If you declare Static something As Integer within a method, it will behave like in VB6.
Guido Domenici
A: 

Often those sorts of variables are used to maintain iterators. C# has these built directly into the language via the yield keyword. Here's an example:

IEnumerable<int> TimesTable(int table)
{
    for (int i=0 ; i<12 ; i++)
    {
        yield return i * table;
    }
}

In this example, we create the values in the n times table where n is specified by the caller. We can use this anywhere an iterator is used, such as in a foreach loop:

foreach (var value in TimesTable(3))
{
    Console.Write(""+ value + " ");
}

...which produces:

3 6 9 12 15 18 21 24 27 30 33 36  

In C++, this might have used static variables like the ones you described from VB (I'm not a VB guy so I don't know the VB syntax):

int TimesTable(int table) {
    static i = 1;
    if (i == 12) {
        i = 1;
    }
    return i++ * table;
}

The C# version is better than the C++ (or VB) equivalent becuase the iterator can be cancelled early and there can be multiple iterators active at any given time. These things are not true for the C++ version without more work from the developer. On the downside, it means that the only time anything like a static variable is valid in C# is during an iterator implementation, and the value does not persist beyond that scope.

I hope that is of some use to you.

Damian Powell
Yes, I am aware of iterators, but that's not the specific thing I need, anyways, thanks.
blez