我需要存储一个语言代码字符串,例如“en”,它总是包含 2 个字符。
将类型定义为“String”还是“Char”更好?
private string languageCode;
对比
private char[] languageCode;
或者还有其他更好的选择吗?
这两个如何存储在内存中?分配值时将为它们分配多少字节或位?
我需要存储一个语言代码字符串,例如“en”,它总是包含 2 个字符。
将类型定义为“String”还是“Char”更好?
private string languageCode;
对比
private char[] languageCode;
或者还有其他更好的选择吗?
这两个如何存储在内存中?分配值时将为它们分配多少字节或位?
它们是如何存储的
thestring
和 thechar[]
都存储在堆上 - 所以存储是相同的。在内部,我会假设一个string
简单的封面char[]
包含许多额外的代码,以使其对您有用。
此外,如果您有很多重复的字符串,您可以使用Interning来减少这些字符串的内存占用。
更好的选择
我更喜欢字符串 - 数据类型是什么以及您打算如何使用它会立即变得更加明显。人们也更习惯于使用字符串,因此可维护性不会受到影响。您还将从为您完成的所有样板代码中受益匪浅。微软也付出了很多努力来确保该string
类型不是性能猪。
分配大小
我不知道分配了多少,我相信字符串非常有效,因为它们只分配足够的空间来存储 Unicode 字符——因为它们是不可变的,所以这样做是安全的。如果不分配新数组中的空间,数组也无法调整大小,所以我再次假设它们只抓取他们需要的东西。
备择方案
根据您的信息,只有 20 种语言代码并且性能是关键,您可以声明自己的枚举以减少表示代码所需的大小:
enum LanguageCode : byte
{
en = 0,
}
这将只需要 1 个字节,而不是 4+ 两个char
(在一个数组中),但它确实将可用LanguageCode
值的范围限制为byte
- 对于 20 个项目来说足够大。
您可以使用运算符查看值类型的大小sizeof()
:sizeof(LanguageCode)
。枚举只不过是底层的类型,它们默认为int
,但正如您在我的代码示例中看到的那样,您可以通过“继承”新类型来更改它。
简短回答:使用字符串
长答案:
private string languageCode;
AFAIK 字符串存储为以长度为前缀的字符数组。在堆上实例化一个 String 对象来维护这个原始数组。但 String 对象不仅仅是一个简单的数组,它支持基本的字符串操作,如比较、连接、子字符串提取、搜索等
尽管
private char[] languageCode;
将存储为一个字符数组,即一个数组对象将在堆上创建,然后它将用于管理您的字符。但它仍然有一个长度属性,该属性存储在内部,因此与字符串相比没有明显的内存节省。虽然大概 Array 比 String 更简单,并且可能具有更少的内部变量,因此提供了更低的内存占用空间(这需要验证)。
但是 OTOH 你失去了在这个 char 数组上执行字符串操作的能力。即使是字符串比较之类的操作现在也变得很麻烦。长话短说使用字符串!
这两个如何存储在内存中?分配值时将为它们分配多少字节或位?
.NET 中的每个实例都按如下方式存储:一个IntPtr
大小的字段用于类型标识符;另一个用于锁定实例;余数是四舍五入的实例字段数据IntPtr
。因此,在 32 位平台上,每个实例占用 8 个字节 + 字段数据。
这适用于 astring
和 a char[]
。这两者也将数据的长度存储为一个 IntPtr 大小的整数,然后是实际数据。因此,一个两个字符string
和一个两个字符char[]
,在 32 位平台上,将占用 8+4+4 = 16 个字节。
在恰好存储两个字符时减少这种情况的唯一方法是将实际字符或包含字符的结构存储在字段或数组中。所有这些将只消耗 4 个字节的字符:
// Option 1
class MyClass
{
char Char1, Char2;
}
// Option 2
class MyClass
{
CharStruct chars;
}
...
struct CharStruct { public char Char1; public char Char2; }
MyClass
每个实例最终将使用 8 个字节(在 32 位机器上)加上 4 个字节用于字符。
// Option 3
class MyClass
{
CharStruct[] chars;
}
这将使用 8 个字节作为 MyClass 开销,加上 4 个字节作为chars
reference,加上 12 个字节作为数组的开销,加上数组CharStruct
中的每个字节。
如果您想准确存储 2 个字符,并且最有效地做到这一点,请使用结构:
struct Char2
{
public char C1, C2;
}
使用此结构通常不会导致新的堆分配。它只会扩大现有对象的大小(尽可能少的数量)或消耗非常便宜的堆栈空间。
字符串确实有一个指针长度的大小开销,即 32 位进程为 4 个字节,64 位进程为 8 个字节。但话又说回来,字符串提供的回报比 char 数组要多得多。
如果您的应用程序使用许多短字符串,并且您不需要经常使用它们的字符串属性和方法,那么您可能可以保护几个字节的内存。但是如果你想将它们中的任何一个用作字符串,你首先必须创建一个新的字符串实例。我看不出这将如何帮助您获得足够的内存以值得麻烦。
String 只是在内部实现了一个 char 类型的索引器,我们可以说这string
相当于char[]
type 有很多额外的代码来使它对你有用,因此,就像一个数组一样,它总是存储在堆上。
一个数组不能在不分配新空间的情况下进行操作,字符串也是如此,因此它是不可变的
字符串实现IEnumerable<char>
值得注意的一点:当您将字符串传递给函数时,它是按值传递,除非使用ref