Does C # support the use of static local variables?

Related: How to create a static local variable in Java?




Sorry if this is a duplicate; I was sure that this would have been set earlier, and I looked, but did not find a cheat.

Is it possible to create a static local variable in C #? If so, how?

I have a static private method that is rarely used. the static method uses a regular expression, which I would like to initialize once and only when necessary.

In C, I could do this with a local static variable. Can I do this in C #?

When I try to compile this code:

private static string AppendCopyToFileName(string f) { static System.Text.RegularExpressions.Regex re = new System.Text.RegularExpressions.Regex("\\(copy (\\d+)\\)$"); } 

... this gives me an error:

error CS0106: The 'static' modifier is not valid for this element




If there is no local static variable, I suggest that I could get closer to what I need by creating a tiny new private static class and inserting both the method and the variable (field) into the class. Like this:

 public class MyClass { ... private static class Helper { private static readonly System.Text.RegularExpressions.Regex re = new System.Text.RegularExpressions.Regex("\\(copy (\\d+)\\)$"); internal static string AppendCopyToFileName(string f) { // use re here... } } // example of using the helper private static void Foo() { if (File.Exists(name)) { // helper gets JIT'd first time through this code string newName = Helper.AppendCopyToFileName(name); } } ... } 

Thinking about it more, using a helper class like this, you will get a big net savings in efficiency because the Helper class will not be JIT'd or loaded if necessary. Right?

+20
c # static
Mar 06 '10 at 16:20
source share
13 answers

No, C # does not support this. You can come up with:

 private static System.Text.RegularExpressions.Regex re = new System.Text.RegularExpressions.Regex("\\(copy (\\d+)\\)$"); private static string AppendCopyToFileName(string f) { } 

The only difference here is the visibility of 're'. This is exposed to the class not only by the method.

The re variable will be initialized the first time you use the containing class. So keep it in a specialized small class.

+11
Mar 06 '10 at 16:41
source share

Unfortunately not. I really loved this opportunity in C.

I have an idea what you can do.

Create a class that provides access to specific instance values ​​that will be stored statically.

Something like that:

 class MyStaticInt { // Static storage private static Dictionary <string, int> staticData = new Dictionary <string, int> (); private string InstanceId { get { StackTrace st = new StackTrace (); StackFrame sf = st.GetFrame (2); MethodBase mb = sf.GetMethod (); return mb.DeclaringType.ToString () + "." + mb.Name; } } public int StaticValue { get { return staticData[InstanceId]; } set { staticData[InstanceId] = value; } } public MyStaticInt (int initializationValue) { if (!staticData.ContainsKey (InstanceId)) staticData.Add (InstanceId, initializationValue); } } 

Can be used this way ...

 class Program { static void Main (string[] args) { // Only one static variable is possible per Namespace.Class.Method scope MyStaticInt localStaticInt = new MyStaticInt (0); // Working with it localStaticInt.StaticValue = 5; int test = localStaticInt.StaticValue; } } 

This is not an ideal solution, but an interesting toy.

You can have only one static variable of this type in the namespace. Class.Method. Will not work in property methods - they are all solved with the same name - get_InstanceId.

+5
Mar 06 '10 at 16:22
source share

Why not create a static readonly member only for static readonly in your class and initialize it in a static constructor?

This will give you the same performance gain - it will only be initialized once.

+5
Mar 06 '10 at 16:38
source share

Not in C #, only in Visual Basic.NET:

 Sub DoSomething() Static obj As Object If obj Is Nothing Then obj = New Object Console.WriteLine(obj.ToString()) End Sub 

VB.NET has a lot of nice things that C # doesn't have, so I choose VB.NET.

+4
Apr 25 '16 at 10:25
source share

How about this, since you want it to be initialized if used:

 private static System.Text.RegularExpressions.Regex myReg = null; public static void myMethod() { if (myReg == null) myReg = new Regex("\\(copy (\\d+)\\)$"); } 
+2
Mar 06 '10 at 17:31
source share

C # does not support static local variables. In addition to what was posted above, here is a link to an MSDN blog post on this topic:
http://blogs.msdn.com/b/csharpfaq/archive/2004/05/11/why-doesn-tc-support-static-method-variables.aspx

+1
Nov 24 '10 at 7:22
source share

According to the answers of Henk and BarretJ, I think you can avoid the initialization cost and get even closer using the property,

 private Regex myReg = null; private Regex MyReg { get { if (myReg == null) myReg = new Regex("\\(copy (\\d+)\\)$"); return myReg; } } 

Then just use MyReg (note the uppercase "M" in MyReg) everywhere in your code. The best part about this solution is that (although getter is a function call under the hood), property semantics mean that you can write code as if MyReg was a variable.

The above describes how I configure "runtime constants" that require one-time initialization at runtime.

I do the same using nullable types. For example,

 private bool? _BoolVar = null; private bool BoolVar { get { if (_BoolVar.HasValue) return (bool)_BoolVar; _BoolVar = /* your initialization code goes here */; return (bool)_BoolVar; } } 

Then just use BoolVar, like a normal normal bool in your code. I don’t use the internal _BoolVar (backup storage for the BoolVar property) because I just don’t need to, remember that this looks like a run-time constant, so there is no setting. However, if for some reason I needed to change the value of the runtime constant, I would do it directly with a variable with a null value of _BoolVar.

Initialization can be quite complicated. But it is executed only once and only at the first access to the property. And you have the choice to force reinitialization of the runtime constant value by setting _BoolVar to null.

+1
Oct 11 '14 at 0:50
source share

Sure. You just need to declare a private static variable outside the method.

  private static readonly System.Text.RegularExpressions.Regex re = new System.Text.RegularExpressions.Regex( "\\(copy (\\d+)\\)$" ); private static string AppendCopyToFileName( string f ) { //do stuff. } 

This is effectively what you are doing, with the only difference being that "re" is visible to the whole class, and not just to this method.

0
Mar 06 '10 at 17:21
source share

I did not see a good general solution to this, but I thought I'd come up with my own. However, I should note that for the most part (not always) the need for static local variables is probably a sign that you should reorganize your code for reasons that have been expressed by many people; state is something for an object, not a method. However, I like the idea of ​​limiting the scope of variables.

Without further ado:

 public class StaticLocalVariable<T> { private static Dictionary<int, T> s_GlobalStates = new Dictionary<int, T>(); private int m_StateKey; public StaticLocalVariable() { Initialize(default(T)); } public StaticLocalVariable( T value ) { Initialize(value); } private void Initialize( T value ) { m_StateKey = new StackTrace(false).GetFrame(2).GetNativeOffset(); if (!s_GlobalStates.ContainsKey(m_StateKey)) { s_GlobalStates.Add(m_StateKey, value); } } public T Value { set { s_GlobalStates[m_StateKey] = value; } get { return s_GlobalStates[m_StateKey]; } } } 

Of course, this is not thread safety, but it does not require too much work. It can be used like this:

 static void Main( string[] args ) { Console.WriteLine("First Call:"); Test(); Console.WriteLine(""); Console.WriteLine("Second Call:"); Test(); Console.ReadLine(); } public static void Test() { StaticLocalVariable<int> intTest1 = new StaticLocalVariable<int>(0); StaticLocalVariable<int> intTest2 = new StaticLocalVariable<int>(1); StaticLocalVariable<double> doubleTest1 = new StaticLocalVariable<double>(2.1); StaticLocalVariable<double> doubleTest2 = new StaticLocalVariable<double>(); Console.WriteLine("Values upon entering Method: "); Console.WriteLine(" intTest1 Value: " + intTest1.Value); Console.WriteLine(" intTest2 Value: " + intTest2.Value); Console.WriteLine(" doubleTest1 Value: " + doubleTest1.Value); Console.WriteLine(" doubleTest2 Value: " + doubleTest2.Value); ++intTest1.Value; intTest2.Value *= 3; doubleTest1.Value += 3.14; doubleTest2.Value += 4.5; Console.WriteLine("After messing with values: "); Console.WriteLine(" intTest1 Value: " + intTest1.Value); Console.WriteLine(" intTest1 Value: " + intTest2.Value); Console.WriteLine(" doubleTest1 Value: " + doubleTest1.Value); Console.WriteLine(" doubleTest2 Value: " + doubleTest2.Value); } // Output: // First Call: // Values upon entering Method: // intTest1 Value: 0 // intTest2 Value: 1 // doubleTest1 Value: 2.1 // doubleTest2 Value: 0 // After messing with values: // intTest1 Value: 1 // intTest1 Value: 3 // doubleTest1 Value: 5.24 // doubleTest2 Value: 4.5 // Second Call: // Values upon entering Method: // intTest1 Value: 1 // intTest2 Value: 3 // doubleTest1 Value: 5.24 // doubleTest2 Value: 4.5 // After messing with values: // intTest1 Value: 2 // intTest1 Value: 9 // doubleTest1 Value: 8.38 // doubleTest2 Value: 9 
0
Jul 23 '13 at 17:39
source share

Three years later ...

You can approximate it using a captured local variable.

  class MyNose { private static void Main() { var myNose= new MyNose(); var nosePicker = myNose.CreatePicker(); var x = nosePicker(); var y = nosePicker(); var z = nosePicker(); } public Func<int> CreatePicker() { int boog = 0; return () => boog++; } } 
0
Dec 04 '13 at 9:15
source share

Nesting related members in an inner class, as you have shown, is the cleanest, most likely. You do not need to push your parent method into an inner class if the static variable can somehow get caller information.

 public class MyClass { ... class Helper { static Regex re = new Regex("\\(copy (\\d+)\\)$"); string caller; internal Helper([CallerMemberName] string caller = null) { this.caller = caller; } internal Regex Re { //can avoid hard coding get { return caller == "AppendCopyToFileName" ? re : null; } set { if (caller == "AppendCopyToFileName") re = value; } } } private static string AppendCopyToFileName(string f) { var re = new Helper().Re; //get new Helper().Re = ...; //set } private static void Foo() { var re = new Helper().Re; //gets null new Helper().Re = ...; //set makes no difference } } 
  • You can avoid hard-coding method names in a property by using some expression tree tricks.

  • You can avoid the helper constructor and make the property static, but you need to get caller information inside the property using StackTrace .

Finally, const always exists inside the method, but then one, it is not a variable, two, only compile-time constants are allowed. Just declare.

0
Jan 12 '14 at 23:19
source share

I developed a static class that handles this problem in a rather simple way:

 using System.Collections.Generic; using System.Runtime.CompilerServices; public static class StaticLocal<T> { static StaticLocal() { dictionary = new Dictionary<int, Dictionary<string, Access>>(); } public class Access { public T Value { get; set; } public Access(T value) { Value = value; } } public static Access Init(T value, [CallerFilePath]string callingFile = "", [CallerMemberName]string callingMethod = "", [CallerLineNumber]int lineNumber = -1) { var secondKey = callingFile + '.' + callingMethod; if (!dictionary.ContainsKey(lineNumber)) dictionary.Add(lineNumber, new Dictionary<string, Access>()); if (!dictionary[lineNumber].ContainsKey(secondKey)) dictionary[lineNumber].Add(secondKey, new Access(value)); return dictionary[lineNumber][secondKey]; } private static Dictionary<int, Dictionary<string, Access>> dictionary; } 

It can be implemented as part of a method like this:

 var myVar = StaticLocal<int>.Init(1); Console.Writeline(++myVar.Value); 

Each subsequent method call, the value contained in myVar.Value will be the last one when it was set so that repeated calls invoked it to output a sequence of natural numbers. The Init () function sets a value only if it has not been previously initialized. Otherwise, it simply returns a reference to the object containing the value.

It uses the attributes [CallerFilePath], [CallerMemberName] and [CallerLineNumber] to track which subject the dictionary refers to. This eliminates the possibility of collisions between methods with the same names or calls from the same line numbers.

A few warnings about use:

  • As others have argued, it is worth considering whether what you are doing is necessary to use static local variables. Their use can sometimes be a sign that your design is flawed and may use some refactoring.
  • This method of solving the problem involves a couple of levels of indirection that slow down your program. It should be used only if it justifies this cost.
  • Static local variables can help you cope with too many members declared in your class, and thus distinguish between where they are used. This should be comparable to the execution time, but sometimes it may be worth it. On the other hand, having so many members declared in a class may indicate design issues that are worth considering.
  • Since these values ​​remain in memory after completing their methods, you must remember that using them to store large chunks of memory will prevent garbage collection until the program terminates, which will reduce your available resources.

This approach is likely to be redundant for most cases when you want to use static local variables. Using indirectness to process individual files, methods, and lines may not be necessary for your project, in which case you can simplify it to meet your needs.

0
Apr 18 '16 at 18:00
source share

This is a duplicate of Why does C # not support local static variables like C?

But still, I think you will find my answer useful.

0
Jan 11 '19 at 12:26
source share



All Articles