简体   繁体   中英

modify a value-type variable in a using statement

In C#, if I have the following struct:

internal struct myStruct : IDisposable
{
    public int x;

    public void Dispose()
    {
        x = 0;
    }
}

then do this in Main:

using (myStruct myStruct = new myStruct())
{
   myStruct.x = 5;
}

it fails saying that myStruct is readonly. That makes sense as myStruct is a value-type.

Now if I add the folling function to the struct:

public void myfunc(int x)
{
    this.x = x;
}

and change the Main code to this:

using (myStruct myStruct = new myStruct())
{
    myStruct.myfunc(5);
    Console.WriteLine(myStruct.x);
}

it works. Why ?

The short answer is "because the C# specification says so". Which, I admit, may be a bit unsatisfying. But that's how it is.

The motivation is, I'm sure, as commenter Blogbeard suggests: while it's practical to enforce read-only on the field access, it's not practical to do so from within a type. After all, the type itself has no way to know how a variable containing a value of that type was declared.

The key part of the C# specification (from the v5.0 spec) is here, on page 258 (in the section on the using statement):

Local variables declared in a resource-acquisition are read-only, and must include an initializer. A compile-time error occurs if the embedded statement attempts to modify these local variables (via assignment or the ++ and operators), take the address of them, or pass them as ref or out parameters.

Since in the case of a value type, the variable itself contains the value of the object rather than a reference to an object, modifying any field of the object via that variable is the same as modifying the variable, and is so a "modification via assignment", which is specifically prohibited by the specification.

This is exactly the same as if you had declared the value type variable as a field in another object, with the readonly modifier.

But note that this is a compile-time rule, enforced by the C# compiler, and that there's no way for the compiler to similarly enforce the rule for a value type that modifies itself.


I will point out that this is one of many excellent reasons that one should never ever implement a mutable value type. Mutable value types frequently wind up being able to be modified when you don't want them to be, while at the same time find themselves failing to be modified when you do want them to be (in completely different scenarios from this one).

If you treat a value type as something that is truly a value, ie a single value that is itself never changing, they work much better and find themselves in the middle of many fewer bugs. :)

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