简体   繁体   中英

C# performance of struct containing a string vs class containing a string

Please check out these two small examples:

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 :).
    }
}

From what I know if I pass struct as a parameter it will make a copy of it someObject.Method(this.cachedStruct); - which in turn will make a copy of a StringValue as string s are immutable it will allocate array in memory for this string which is quite costly operation [pardon me if I made a mistake, please correct me in such a case].

So in this instance I assume it will be faster to use instances of the Class rather than copying StringValue each time. QUESTION: Are my assumptions correct and Class is a better choice for this kind of a situation or is it still more beneficial and faster to use Struct ?

Since String and string are the same. ref - What is the difference between String and string in C#? . I cannot use String in struct to prevent it from creating a new string object when struct has been passed as a parameter.

To better address the issue, here is another example. Sorry if it's a bit rough example.

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.
    }
}

My understanding is that if I use Struct without changing string value it will still allocate memory for StringValue each time I pass it as a parameter. While when using Class and passing its instance as a parameter - it will pass Class instance as a reference type without copying values, thus not allocating any memory for StringValue .

My question might seem similar to C#, struct vs class, faster? [duplicate] and other questions (I believe I have gone through them all (the ones that struct vs class performance)) but none of them have given me an answer.

The string is for example at address 0x0110 and called "hello" . The struct does not store the string itself, it only stores the reference to this string. Thus the struct will only store "0x0110" . When you copy the struct, the struct copy will store the same reference "0x0110" . Not the string, just the reference. No new string object will be created. But when you change the string in the struct copy, for example from "hello" to "bla" , a new string will be created at a new address. For example "bla" will be at address 0x0220 . the struct copy will then store "0x0220" instead of "0x0110" . The original struct will still store "0x0110" . You are now having 2 strings in memory at different adresses.

0x0110 "hello"
0x0220 "bla"

PS: that is a simplification of what really happens.

You seem to not know exactly how reference and value types work.

You have variable a of a type that is either class or a struct. This variable holds a value , thats all a variable is. What the value is depends one whether the type is a reference type or a value type:

  • If its a reference type, the value of a is a reference , that is, a memory address where the referenced object is found.
  • If its a value type, the value of a is the value type itself.

In C#, by default, variables are passed by value. That is, a copy of the variable's value is made:

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

void SomeMethod(SomeType t) { }

b holds a copy of a . And t holds a copy of b .

If SomeType is a reference type (for example string ) then all three variables a , b and t hold the same value; an address to the string instance originally assigned to a .

If SomeType is a value type, then all three variables hold three identical but distinct instances of the value type returned by new SomeType() . The variables that make up the inner state of said value type are themselves copied in the same manner: their value is copied.

Does that make it clearer?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM