我错过了静态字段的一些好处吗?

时间:2017-08-22 17:11:47

标签: c# static

我正在通过Joseph Albahari& amp; Ben Albahari一直是一本很棒的书,正在阅读C#中关于静态字段的主题。他们有这个示例代码,

public class Panda
{
    public string name;
    public static int population;

    public Panda(string n)
    {
        name = n;
        population = population + 1;
    }
}

所以我明白,你实例化更多人口的Panda实例将会变得更多,因为它在Panda类型的所有对象之间共享,但现在我的问题。

为什么?我无法理解为什么我会想要在应用程序中使用此类行为。在对象本身内跟踪全局变量似乎是一种令人困惑的方式。我是否误解了静电场的潜在好处?在哪些情况下这会有用而不会混淆?

4 个答案:

答案 0 :(得分:1)

我认为最好先回顾一下幕后发生的事情。

如果创建静态类,则会在运行时创建单个实例。只要您第一次尝试使用该类型并从那里使用它就会发生。如果您想要延迟加载共享资源,这可以派上用场。它还保证(通过编译器和运行时)您始终只有一个实例。

如果类不是静态但您使用静态成员,则可以构造新实例,但在后台为您维护“静态版本”。这对于您需要跟踪某些内容或者如果您希望在实例之间共享某些内容甚至是其他代码(如果您将该成员公开)的情况非常有用。

就性能而言,如果您需要加速程序并实现(通过对象计数)您实例化一个永远不会改变100次的对象,那么它可能非常有用。也许你想向你的用户展示出生的熊猫数量。理论上你可以在其他地方保持计数,但如果你考虑它,你将需要另一个对象,所以将所有相关的信息和逻辑保持在一起是有意义的。此外,你可以有一个更通用的类型,分为派生的类型,你可能想要跟踪所有这些类型,而不必继续添加逻辑。

考虑以下示例:

public abstract class Animal
{
    private static int _count;
    protected Animal()
    {
        IncrementCount();
    }        
    protected static void IncrementCount()
    {
        _count++;
    }

    public int WorldPopulation()
    {
        return _count;
    }
}

public class Dog : Animal
{

}

public class Cat : Animal
{

}

public class Bird : Animal
{

}

如果我要创建DogCatBird实例,然后检查WorldPopulation()方法的值,我会得到3

Singleton模式也常用这种方法实现。它允许您在内部包含构造时维护单个实例:

public class SingletonSample
{
    private SingletonSample()
    {

    }

    private static SingletonSample _instance;
    public static SingletonSample Instance 
     { 
          get
          {
               if(_instance == null)
                    _instance = new SingletonSample();
               return _instance;
          }
     }

    public bool IsThisTrue()
    {
        return true;
    }
}

请注意,您无法通过类名访问IsThisTrue()方法,您需要一个实例,并且无法直接创建它。它只能由类本身在内部创建:

//Object construction occurs the first time you access the "Instance" property
SingletonSample.Instance.IsThisTrue();

我希望有所帮助。

答案 1 :(得分:0)

  

我无法理解为什么我会想要利用这些   应用程序中的行为。

你永远不想知道游戏中的熊猫数?高分怎么样?

现在,静态字段是否是最好的方法是一种不同的方式 - 有其他模式,但它们的构建和管理往往要复杂得多。

答案 2 :(得分:0)

简答:

考虑缓存是存储计算结果的地方。只要计算费用昂贵,缓存就很有用,但存储很便宜。在C#中,静态变量只是用于实时系统计算的缓存

更长的回答:

理论上,我们可以通过搜索所有对象,然后针对某个子集执行计算来发现我们想要了解的关于正在运行的系统的任何信息。由于这正是垃圾收集器的作用,因此假设的CLI为垃圾收集器提供了正确的挂钩,可以避免使用静态变量。

例如,假设我们想知道我们创建了多少function remel(fdx) { for (var v = fdx; v < myArray.length; v++) { document.getElementById('rswinfav' + v).addEventListener('click', (function (v) { return function () { setFav(v); }; }(v)) ); } } 个对象。好吧,我们需要做的就是向GC询问所有活动对象的列表,然后筛选类型为Widget的对象的列表,然后计算Widget s。

但是示例中存在一些问题:首先,一些Widget对象可能不是活动的(无法访问,因此无法进行状态更改),但我们需要将它们保留在周围只是为了计数目的。即使每个Widget实例的大小只是一个位,如果我们需要保持一百万Widget的计数,我们仍然需要122KB的内存(因为CLR对象是至少4个字节,我们需要几乎4MB来跟踪计数)。另一方面,一个20位变量足以计算一百万。这节省了99.99%(实际CLR的情况下实际为99.99999%)。其次,垃圾收集可能是一项昂贵的操作。即使我们避免了内存压缩的开销,我们也只需要暂停系统。

所以,希望现在很容易理解为什么我们希望能够缓存关于实时系统的某些计算,以及静态变量的有用性。

说了这么多,通常情况下,由于CPU缓存的工作方式,重新计算事物而不是将结果缓存在静态变量中会更好。

答案 3 :(得分:-2)

这是我如何使用静态对象的示例。 我有任务要创建一个带进度条的上传程序处理程序。 并且进度条显示给站点中的所有用户。 因此,在新线程中创建了上载操作,然后将操作结果附加到线程外部的静态对象(进度条),进度条将显示给正在查看站点的所有用户。

可在此处找到更多信息和示例 What is the use of static variable in C#? When to use it? Why can't I declare the static variable inside method?