可以使用静态成员变量来缓存静态类中的值吗?

时间:2017-04-21 09:42:25

标签: c# caching static-methods

我遇到过这段代码,看起来原始开发人员试图使用静态字符串来缓存静态类中的值。

public static class GetStringFromSomeProcess
{
    private static string theAnswer;

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

据我所知,这不起作用,因为您无法实例化GetStringFromSomeProcess类,每次使用GoGetTheAnswerFromALongRunningProcess时都会调用GetString。我错过了什么吗?

3 个答案:

答案 0 :(得分:3)

你说的是,这个类不能被实例化,但是该类将存在于应用程序中。

因此,只有第一次访问该属性时,才会调用方法GetStringFromSomeProcess。在此之后的每隔一段时间,== null的检查将解析为false,并且将返回第一次通话评估的值。

答案 1 :(得分:3)

这样可以正常工作 - theAnswer只有一个实例,因为它是静态的 - 并且(也因为它是静态的)可以从公共静态属性访问它。这意味着对其进行的任何更改都将对访问它的所有代码可见。因此,第一次调用GetString会将theAnswer设置为非空,后续调用将不会调用GetStringFromSomeProcess()

但是,您发布的解决方案不是线程安全的,因为多个线程可以同时调用GoGetTheAnswerFromALongRunningProcess()

.Net提供Lazy类来解决此问题,如下所示:

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

您向Lazy<T>类的构造函数提供了一个方法,它可以在需要时调用它以创建它正在包装的对象。在上面的示例中,我将GoGetTheAnswerFromALongRunningProcess传递给它的构造函数。

另请注意,拥有一个可能需要很长时间才能返回的属性通常是一个坏主意。最好把它变成一种方法:

public static string GetString()
{
    return _theAnswer.Value;
}

答案 2 :(得分:0)

如果没有创建GetStringFromSomeProces类的对象,它是否正常工作?由于字符串theAnswer也是静态的,它可能有效,但我想知道该变量何时初始化。通常,您会像使用GetStringFromSomeProcess类的初始化建议一样对其进行编码。

Main.cs

...
GetStringFromSomeProcess getString = new GetStringFromSomeProcess();
string answer = getString.theAnswer();
...

<强> GetStringFromSomeProcess.cs

public class GetStringFromSomeProcess
{
    private string _theAnswer;

    public string theAnswer
    {
        get
        {
            if(theAnswer == null)
            {
                GoGetTheAnswerFromALongRunningProcess getAnswer = new GoGetTheAnswerFromALongRunningProcess();
                _theAnswer = getAnswer.GetAnswer();
            }
            return _theAnswer;
        }
    }
}