简体   繁体   中英

Assigning value to member of nullable struct in C#

In C#, I have a struct like this:

public struct Slab
{   public float[] sizeM;
    public string textureSrc;
    //more members, not relevant here...
}

And another like this:

public struct Tombstone
{   public Slab mainSlab;
    public Slab? basing;
    //more...
}

Now, I want to modify members of basing:

uiState[0].stone.basing.Value.sizeM[2] = Int32.Parse(breadthField.Value) / 100.0f;
uiState[0].stone.basing.Value.textureSrc = fileName;

( uiState[0].stone is of type Tombstone )

First of these two calls works correctly, as I'm just changing a member of the array in basing , not the array itself. However, the second complains:

Cannot modify the return value of 'Slab?.Value' because it is not a variable

It works if I do the same to mainSlab which is not nullable. Is there a way to do this without copying the whole basing to a local variable for changes?

Is there a way to do this without copying the whole basing to a local variable for changes?

No, because Nullable<T> doesn't provide direct access to the underlying value field. You can't modify it "in place".

There are all kinds of little issues like this when you use mutable structs. I'd strongly advise you to use classes or immutable structs whenever possible, to avoid these corner cases.

Frankly, the main error here is almost certainly: having a mutable struct. Now, there are scenarios where mutable structs make sense, but those scenarios are narrow , and this almost certainly isn't one of them.

Frankly, your code will be much easier to rationalize if you stop doing that ; with recent C#, you can even use readonly struct to help enforce this (and to get better behaviour with in ):

public readonly struct Slab
{   public readonly float[] sizeM;
    public readonly string textureSrc;
    //more members, not relevant here...
}

(personally I'd also consider properties instead of public fields, but that is a separate issue)

Then it becomes obvious that you can only assign the entire object:

Slab? foo = ...
... some logic
foo = new Slab(size, textureSource); // perhaps taking new values from the old

The only other alternative is basically to do the same thing anyway :

Slab? foo = ...
// ...
var innerVal = foo.GetValueOrDefault(); // or .Value if you've already null-checked
// ...
innerVal.textureSrc = ...
foo = innerVal;

There may be many possible fixes for this "problem", depending on the rest of your design and requirements... For example:

public struct Tombstone
{
  public Slab mainSlab;
  public Slab basing;
  public bool hasBasing => basing.sizeM != null;
  //more...
}

To be honest I never user Nullables... Nullable value types, what's next, global rvalues?

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