C#,在设计基本颜色类时正确使用static关键字

时间:2008-11-22 15:41:03

标签: c# static

我正在制作一个Color类,并提供像

这样的标准构造函数
Color(int red, int green, int blue)

然后我想提供一种简单的方法来获得最常见的颜色,比如 Color.Blue,Color.Red。我看到两种可能的选择:

public static readonly Color Red = new Color(255, 0, 0);

public static Color Red { get { return new Color(255, 0, 0); } }

我不完全理解的是,一个优势是否优于另一个优势,以及static关键字的工作原理。我的想法是:第一个创建一个实例,然后该实例在程序的整个持续时间内保留在内存中,并且每次调用Red时,都会使用此实例。后者仅在首次使用时创建一些内容,但每次都会创建一个新实例。如果这是正确的,那么我认为如果我提供了很多预定义的颜色,那么第一个会使用大量不必要的内存吗?因此,每次我猜它是内存使用量与实例化对象的运行时开销。

我的推理是否正确?在设计类和使用static关键字时,对最佳实践的任何建议都会很棒。

4 个答案:

答案 0 :(得分:7)

我猜你可能已经意识到该框架提供了一个Color结构。我猜你正在为练习创建一个Color课程。

您对static关键字的含义表示不确定,尽管您已正确使用它。当static应用于类或结构的成员时,意味着该成员作为一个整体属于该类,并且不适用于单个实例。静态数据成员(字段)只创建一次;实例没有自己的副本。在没有实例引用的情况下调用静态函数(方法和属性)。

就内存使用情况而言,在你的情况下我不会太担心它。您的Color类不应该为每个实例使用多个字节(例如,框架的Color结构在一个32位int中存储红色,绿色,蓝色和alpha。 )。如果您的Color真的是class而不是struct,那么您的开销会有更多的字节数(每个实例都会有一个额外的32位v-table / typeinfo指针,每个引用都是一个额外的32位),但即便如此,你所说的每个实例大约12个字节。如果预定义了100种不同的颜色,则使用< = 1200字节。真的没什么大不了的。

但是有懒惰实例化的原因。有些类使用大量内存,有些类需要有限的系统资源,有些需要花费很长时间来构建自己,等等。对于这些类,有时最好使用模式如:

class Heavy{
    static Heavy first;
    static Heavy second;

    public static Heavy First{
        get{
            if(first == null)
                first = new Heavy();
            return first;
        }
    }
    public static Heavy Second{
        get{
            if(second == null)
                second = new Heavy();
            return second;
        }
    }
}

另一个考虑因素是可变性。您的Color类是可变的还是不可变的?换句话说,您的类的实例是否可以更改其值,或者一旦创建它们,它们是否始终表示相同的值?

如果您的Color是可变的,那么拥有静态“红色”访问器的唯一正确方法将是您的第二个示例,您可以在每个访问时创建一个新的。这样一来,某人就无法做到:

Color.Red.G = 255;

并使单个共享Color.Red实例实际上代表黄色,而不是。

但请记住,例如:

for(int y = 0; y < bmp.Height; y++)
for(int x = 0; x < bmp.Width; x++)
    if(bmp.GetPixel(x, y) == Color.Red))
        MessageBox.Show("Found a red pixel!");

将创建Color类的很多实例。当然,它们将在以后被垃圾收集,但这仍然是上面第一个构造的一个案例论证(或者我给出的“重”例子)。

现在,如果你的Color实际上是一个结构,那么这是一个略有不同的故事。当new结构时没有堆分配,并且没有v表或引用指针,因此真正考虑的是构造函数需要多长时间。

答案 1 :(得分:3)

你的推理和识别似乎是合理的。如果你看一下System.Drawing.Color结构,你会看到它使用第二种技术。初始化新结构的开销很小,所以这可能比预先创建大量已知颜色更好。

我希望Color是一个不可变的结构。但是如果你打算创建一个类,那么如果你决定使用第一种技术,你需要确保它是不可变的。

答案 2 :(得分:1)

我将添加关于使用静态的一个注意事项是,您应该确保不要滥用它来执行存储全局数据等操作。

如果您确实需要至少在WPF中使用全局数据,那么该模式将具有一个静态属性,该属性引用其自身的非静态实例。例如Application.Current。这是我为我的应用程序复制的模式。

答案 3 :(得分:0)

正如你所说,第一个将创建只创建一个颜色的实例:

public static readonly Color RED = new Color(255, 0, 0);

在幕后我相信在运行时它只会在第一次被调用时实例化。但是我没有在调试器中为自己检查过它。

正如你所说的静态getter替代方案,你提供的实现,将在你调用它时不经意地填满堆。原因是每次调用都会创建一个 new 对象。

如果你真的想要使用getter替代但不填充堆,那么至少也要将Color类的创建设置为静态。像这样:

private static readonly Color RED = new Color(255, 0, 0);
    // RED is created once when it is invoked for the first time.

public static Color Red { 
    get { 
        return RED; 
            // Will return a created RED object or create one 
            // for the first time.
    } 
}