【问题标题】:Can a static member variable be used to cache a value in a static class?静态成员变量可以用来缓存静态类中的值吗?
【发布时间】:2017-04-21 09:42:24
【问题描述】:

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

public static class GetStringFromSomeProcess
{
    private static string theAnswer;

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

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

【问题讨论】:

  • 为什么需要实例化 GetStringFromSomeProcess ?第一次调用GetStringtheAnswer 将不再为null,因此不再调用具有可怕名称的方法

标签: c# caching static-methods


【解决方案1】:

这可以正常工作 - 只有一个 theAnswer 实例,因为它是静态的 - 并且(也因为它是静态的)它可以从公共静态属性访问。这意味着对它所做的任何更改都将对访问它的所有代码可见。所以第一次调用GetString 会将theAnswer 设置为非null,后续调用不会调用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&lt;T&gt; 类的构造函数提供一个方法,它可以在需要时调用该方法以创建它正在包装的对象。在上面的示例中,我将GoGetTheAnswerFromALongRunningProcess 传递给它的构造函数。

另请注意,拥有可能需要很长时间才能归还的房产通常是个坏主意。最好把它做成一个方法:

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

【讨论】:

  • 这个答案中有很多有用的东西,我还在消化 - 谢谢。我不明白的是在调用GetStringFromSomeProcess.GetString 之后为什么 GetStringFromSomeProcess 没有超出范围并且“缓存”变量丢失。我们的意思是,一旦使用 GetString,它就会在应用程序的整个生命周期内挂起,这不是我所期望的。
  • @jonaglon 在您的原始代码中调用GetString 时,它首先检查theAnswer 以查看它是否为空,只有当它为空时才会调用GoGetTheAnswerFromALongRunningProcess() 并分配(大概非空)结果到theAnswer。第一次之后,theAnswer 将不再为空,因此GoGetTheAnswerFromALongRunningProcess() 将不再被调用。
【解决方案2】:

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

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

【讨论】:

  • 所以一个静态类被实例化一次,第一次被使用并且在应用程序的整个生命周期中都存在?我想我认为因为它是静态的,所以它可能会被垃圾收集,因为它在使用后不在范围内。
  • 是的,没错。它在应用程序处于活动状态期间保持不变。它永远不会被垃圾收集,因为它总是可用的。我希望这会有所帮助!
【解决方案3】:

如果不创建 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;
        }
    }
}

【讨论】:

  • 因为 GetStringFromSomeProcess 是静态的 new GetStringFromSomeProcess() 不是有效代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-25
  • 2013-07-02
  • 1970-01-01
相关资源
最近更新 更多