常量值会被存储在每个实例中吗?

3

对于这样的类型:

public class BlurEffect
{
    public const string Name = "Blur";

    public int Amount {get;set;}
}

我有几个成员像.Name,在所有成员中都是相同的,我应该将其静态化吗?

我只是不希望它被存储在每个实例中,或使用比必要更多的资源,并且它们还应该是只读的。

最后,我希望能够对其进行实例访问,这样我就可以说:

blurEffect.Name

我应该创建一个返回私有静态变量的Name属性吗?这是最好的方法吗?

4个回答

6
在C#中,常量实际上是在编译时解析的。编译器会在使用处将其替换为值,因此“变量”(Name)在生成的编译IL中实际上并不存在。
另外,字符串常量会被interned处理,因此无论使用多少次,“Blur”的副本都只会加载一次。
个人建议使用私有常量和公共变量:
public class BlurEffect
{
    private const string name = "Blur";
    public string Name { get { return name; } }

    public int Amount {get;set;}
}

这将为您提供基于实例的用法,并仍然具有您可以操作的单个常量。

1
@Joan:在编译时,它会像您在那里放置“int”值一样运行。因此,如果您有一个常量(即:private const int myConstant = 4;),然后写入:int myVariable = myConstant;,它将编译为完全相同的代码,就好像您写了:int myVariable = 4; - Reed Copsey
3
@Joan: 在 C# 中这是不合法的。常量必须始终是编译时已知的值。 - Reed Copsey
1
只是出于好奇,你为什么选择创建一个返回常量的getter方法,而不是直接将常量公开呢? - Rob
3
通过使用getter,您可以获得一个可以被JIT内联的内容,并且允许您在以后更改它。这避免了使用常量所带来的一个缺点(版本控制),以防未来装配需要更改该值。 - Reed Copsey
2
是的,这样做可以使常量值仅内联到属性访问器中,而不是内联到所有其他用法中,这些用法可能在您更改常量时不会重新编译,因为它们可能位于其他程序集中。 - KeithS
显示剩余4条评论


1

我个人从未遇到过public const变量的任何问题。但是,需要考虑一件事情,即如果以后需要将const更改为非常量(或在某人获取常量值时需要进行任何形式的处理),那么您将破坏二进制API。

这意味着,如果这是类库范围内的,则如果稍后进行此类更改,则链接到您的类库的每个项目都必须重新编译。您不能只是简单地插入DLL来进行更新。


3
请注意,“常量变量”本身就是一个矛盾词。根据定义,常量并不属于变量。 - Eric Lippert
不错,Eric,我从没想过那个。应该说“const value”吗? - Joan Venge
1
@Eric... 嗯,无论是否矛盾,很多人都这么说。 “该类包含一个常量值”听起来很奇怪。“该类包含一个常量变量”对我来说不奇怪。也许我们应该在英语.se上继续讨论? :) - Earlz
2
我会说“这个类包含一个常量” - 不需要其他任何东西 - “常量”本身就是一个名词。 - Reed Copsey

1

.NET中的常量有点奇怪。当您定义一个常量时,编译器会在源代码中强制执行面向对象的约定,但是当编译器创建程序集时,任何引用此常量的程序集(包括您声明它的程序集)都会将对常量引用的调用替换为对存储在本地程序集清单中的相同值的引用(该清单存储大多数“文字”)。因此,常量实际上是按程序集存储的,并且对于程序集中使用该常量的每个使用而言都是“静态”的。问题是,如果更改常量,则必须重新编译引用常量的任何程序集,以便刷新其他程序集上的清单。

就您的情况而言,我会将该值定义为静态,并通过属性公开它。这将防止简单嵌入该值,并将其放置在对象的静态副本中,由当前AppDomain中需要它的任何程序集从一个位置引用(这基本上意味着它在应用程序中的任何地方都是相同的,除了涉及应用程序池或子域的某些特殊情况)。

更多信息:您的常量有多常量?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接