包含字符串的结构与包含字符串的 class 的性能

Performance of struct containing a string vs class containing a string

请查看这两个小示例:

public struct Struct
{
    public readonly string StringValue;
    public readonly int IntValue;

    public Struct(string stringValue)
    {
        this.StringValue = stringValue;
        this.IntValue = this.StringValue.GetHashCode(); // Just ignore this assignment, please :).
    }
}

public class Class
{
    public readonly string StringValue;
    public readonly int IntValue;

    public Class(string stringValue)
    {
        this.StringValue = stringValue;
        this.IntValue = this.StringValue.GetHashCode(); // Just ignore this assignment, please :).
    }
}

据我所知,如果我将 struct 作为参数传递,它将复制它 someObject.Method(this.cachedStruct); - 进而将 StringValue 复制为 strings是不可变的,它会在内存中为这个字符串分配数组,这是相当昂贵的操作[如果我犯了错误,请原谅我,在这种情况下请纠正我]。

所以在这种情况下,我认为使用 Class 的实例比每次都复制 StringValue 会更快。问题:我的假设是否正确,对于这种情况 Class 是更好的选择,还是使用 Struct 更有益和更快?

因为 Stringstring 是一样的。参考 - What is the difference between String and string in C#?。 当结构作为参数传递时,我不能在结构中使用 String 来阻止它创建新的 string 对象。

为了更好地解决这个问题,这里是另一个例子。对不起,如果这个例子有点粗糙。

public struct Struct
{
    public string StringValue;
    public int IntValue;

    public Struct(string stringValue)
    {
        this.StringValue = stringValue;
        this.IntValue = this.StringValue.GetHashCode(); // Just ignore this assignment, please :).
    }
}

public class Class
{
    public string StringValue;
    public int IntValue;

    private Struct _niceStruct;

    public void Accept(Struct someStruct)
    {
        someStruct.StringValue = "Something new"; // In this case even if I don't change the value, it was already allocated.
        // Because of copying of struct when it was passed as a parameter.

        Console.WriteLine(this._niceStruct.StringValue); // "Something new".
    }

    public Class(string stringValue)
    {
        this.StringValue = stringValue;
        this.IntValue = this.StringValue.GetHashCode(); // Just ignore this assignment, please :).

        this._niceStruct = new Struct("Old value");

        this.Accept(this._niceStruct);

        Console.WriteLine(this._niceStruct.StringValue); // "Old value".

        // String value was left unaffected.
        // Which [even in the case I wouldn't change the value in the method] means that a new `string` object was allocated when a copy of `Struct` was created.
        // When using `Class` in the same manner - it would change the `string`.
        // New `string` object won't be allocated if value is unchanged.

        // I assume that `string` allocation might be more costly than `Class` allocation in this instance.
    }
}

我的理解是,如果我在不更改 string 值的情况下使用 Struct,每次我将其作为参数传递时,它仍会为 StringValue 分配内存。当使用 Class 并将其实例作为参数传递时 - 它会将 Class 实例作为引用类型传递而不复制值,因此不会为 StringValue.

分配任何内存

我的问题可能看起来类似于 C#, struct vs class, faster? [duplicate] 和其他问题(我相信我已经完成了所有这些问题(结构与 class 性能的问题))但是 none已经给了我答案。

您似乎不完全了解 referencevalue 类型的工作原理。

您有 a 类型的变量 class 或结构。这个变量持有一个,这就是一个变量的全部。值是什么取决于类型是引用类型还是值类型:

  • 如果是引用类型,a的值是一个引用,即被引用对象所在的内存地址。
  • 如果是值类型,a的值就是值类型本身。

在 C# 中,默认情况下,变量按值传递。也就是说,复制了变量值

SomeType a = new SomeType();
var b = a;
SomeMethod(b)

void SomeMethod(SomeType t) { }

b 持有 a 副本 t 持有 b.

的副本

如果SomeType是引用类型(例如string),那么所有三个变量abt都保持相同的值;最初分配给 a.

的字符串实例的地址

如果 SomeType 是一个值类型,那么所有三个变量都包含 相同但不同的 new SomeType() 返回值类型的实例。构成所述值类型的内部状态的变量本身以相同的方式复制:它们的 value 被复制。

这样是不是更清楚了?

例如,字符串位于地址 0x0110 并称为 "hello"。该结构不存储字符串本身,它只存储对该字符串的引用。因此该结构将只存储 "0x0110"。当您复制结构时,结构副本将存储相同的引用 "0x0110"。不是字符串,只是参考。不会创建新的字符串对象。但是,当您更改结构副本中的字符串时,例如从 "hello" 更改为 "bla",一个新字符串将在新地址创建。例如 "bla" 将位于地址 0x0220。然后结构副本将存储 "0x0220" 而不是 "0x0110"。原始结构仍将存储 "0x0110"。您现在在不同地址的内存中有 2 个字符串。

0x0110 "hello"
0x0220"bla"

PS:这是对真实情况的简化。