Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a static member variable be used to cache a value in a static class?

I've come across this piece of code where it looks like the original developer has tried to use a static string to cache a value in a static class.

public static class GetStringFromSomeProcess
{
    private static string theAnswer;

    public static string GetString
    {
        get
        {
            if(theAnswer == null)
            {
                theAnswer = GoGetTheAnswerFromALongRunningProcess();
            }
            return theAnswer;
        }
    }
}   

As far as I can see this won't work, as you can't instantiate the GetStringFromSomeProcess class, GoGetTheAnswerFromALongRunningProcess will be called every time GetString is used. Am I missing something?

like image 743
jonnarosey Avatar asked Apr 21 '17 09:04

jonnarosey


People also ask

Are static variables cached?

Static data will cache exactly the same as any other data.

Can static variables be reinitialized?

We can also initialize the value of the static variable while declaring it. The syntax for initializing the value of the static variable in C programming language is given below. Note: The value of a static variable can be reinitialized wherever its scope exists.

What is a static member variable?

A variable declared static within a module (but outside the body of a function) is accessible by all functions within that module. However, it is not accessible by functions from other modules. static members exist as members of the class rather than as an instance in each object of the class.

Can a static class have variables?

Class variables are also known as static variables, and they are declared outside a method, with the help of the keyword 'static'. Static variable is the one that is common to all the instances of the class. A single copy of the variable is shared among all objects.


2 Answers

You are right in saying that the class can't be instantiated, but the class will exist within the application.

Therefore, only the first time the property is accessed, will the method GetStringFromSomeProcess be called. Every other time after that, the check for == null will resolve to false and the value evaluated by the first call will be returned.

like image 149
Luke Avatar answered Nov 15 '22 07:11

Luke


This will work fine - there is only one instance of theAnswer because it is static - and (also because it is static) it can be accessed from a public static property. This means that any changes made to it will be visible to all code that accesses it. So the first call to GetString will set theAnswer to non-null, and subsequent calls will not make a call to GetStringFromSomeProcess().

However, the solution you posted is not threadsafe because GoGetTheAnswerFromALongRunningProcess() could be called simultaneously by multiple threads.

.Net provides the Lazy class to solve this issue, as follows:

public static class GetStringFromSomeProcess
{
    private static readonly Lazy<string> _theAnswer = new Lazy<string>(GoGetTheAnswerFromALongRunningProcess);

    public static string GetString
    {
        get
        {
            return _theAnswer.Value;
        }
    }

    public static string GoGetTheAnswerFromALongRunningProcess()
    {
        return "X";
    }
}

You supply to the constructor of the Lazy<T> class a method that it can call when needed in order to create the object that it is wrapping. In the example above, I pass GoGetTheAnswerFromALongRunningProcess to its constructor.

Also note that it's usually a bad idea to have a property that can take a very long time to return. It's better to make it a method:

public static string GetString()
{
    return _theAnswer.Value;
}
like image 25
Matthew Watson Avatar answered Nov 15 '22 07:11

Matthew Watson