Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent assignment to backing fields?

Tags:

c#

I have the following property and backing field:

    private Vector3 _positionB;
    public Vector3 PositionB
    {
        get
        {
            if (_nodeB == null) return _positionB;
            else return _nodeB.Position;
        }
        set
        {
            _positionB = value;
            UpdateMesh();
        }
    }

Problem is, I some times keep assigning the value to the backing field in my class and skipping over the property setter (thus it doesn't update automatically due to logic error).

I would much rather enforce assignment via the property so that the setter runs the relevant function afterwards.

Is there anyway to abstract this out to enforce assignment to only the property within the class?

like image 291
WDUK Avatar asked Jan 23 '20 06:01

WDUK


People also ask

What is backing fields?

A Backing Field is just a field that will be generated for a property in a class only if it uses the default implementation of at least one of the accessors. Backing field is generated only if a property uses the default implementation of getter/setter.

What are the backing fields in the Entity Framework?

Backing fields allow EF to read and/or write to a field rather than a property.

What is backing field in c#?

A private field that stores the data exposed by a public property is called a backing store or backing field. Fields typically store the data that must be accessible to more than one type method and must be stored for longer than the lifetime of any single method.

What is a backing field Java?

What is Backing Field ? Backing field is an autogenerated field for any property which can only be used inside the accessors(getter or setter) and will be present only if it uses the default implementation of at least one of the accessors, or if a custom accessor references it through the field identifier.


1 Answers

  • As an alternative to Obsolete (see my other answer) another option is to define a custom type that encapsulates the behaviour of your PositionB property.
  • You can use a struct or class but I recommend using a struct to eliminate the overhead of having another GC object on the heap and the performance hit of a cache-miss due to reference-locality.
  • And because the backing field is readonly (but it contains a mutable field) it becomes impossible for other members of your class to overwrite the field directly.

    • (Remember that readonly does not mean "immutable" and note that C# does not support C++-style "const-correctness".)

Like so:

class Foo
{
    private struct Vector3Wrapper
    {
        private readonly Foo foo;

        private Vector3 value;

        public Vector3Wrapper( Foo foo )
        {
            this.foo   = foo;
            this.value = default;
        }

        public Vector3 GetValue()
        {
            //return this.foo.nodeB == null ? this.value : this.foo.nodeB.Position;
            return this.foo.nodeB?.Position ?? this.value; // <-- more succinct!
        }

        public void SetValue( Vector3 value )
        {
            this.value = value;
        }
    }

    private readonly Vector3Wrapper positionB;

    public Foo()
    {
        this.positionB = new Vector3Wrapper( this );
    }

    public Vector3 PositionB
    {
        get => this.positionB.GetValue();
        set
        {
            this.positionB.SetValue( value );
            this.UpdateMesh();
        }
    }
}

So this code will cause a compile-time error:

class Foo
{
    // [...]

    void Baz()
    {
        this.positionb = default; // will error because `this.positionB` is readonly (but not immutable)
    }
}
like image 67
Dai Avatar answered Oct 08 '22 03:10

Dai