Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I am building a large, complex data structure with many interconnected objects. As part of this, I have a situation where I need to create an object before I know the values for all the properties. This is so I can pass a reference to that object around inside of a larger data structure, then change it later to allow all the consumers of that object to get the "updated" values.

Tracking the consumers of each object so I can go update their references means I am A) re-implementing a reference counting garbage collector and B) would require an external consumer to modify a class. For obvious reasons, I don't want to implement a garbage collector (or something similar). and allowing external consumers to modify properties means the object is mutable. Immutability is important because I know that many objects in this data structure are going to wind up in Dictionaries after the data structure has been built, but I can safely modify properties until then. Since this is going into a library that will be provided to other users, I must block interactions that will break things like invariants for Dictionaries.

I am implementing this "deferred initialization" concept for properties like this:

class MyClass
{
    private AnotherClass mReference = null;
    public bool Reference
    {
        get
        {
            return this.mReference
        }
        internal set
        {
            if ( this.mReference != null )
            {
                throw new Exception( "This value has already been initialized!" );
            }
            else
            {
                this.mReference = value;
            }
        }
    }
}

I am allowing anything in the internal scope to assign a non-null value to this property exactly once. Once the property has been set, there's no going back.

While C# has a keyword readonly that sort of already does this, readonly constrains the member to only be assigned to via either a static initializer or a constructor in the same class. But at the time the constructor is called, I don't know what the value for this property is!

My problem is I am now using this exact pattern across multiple classes, and I would like to avoid this code duplication.

Does anyone have any suggestions for how I can reduce the code duplication? Maybe a C# keyword like readonly, or some other language feature? Or is this just not possible? Unfortunately, it is not possible to refactor the algorithms such that I can delay instantiation of all objects until all values are known. Think of bidirectional relationships with immutable objects at each end if you need an example of this scenario.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
113 views
Welcome To Ask or Share your Answers For Others

1 Answer

Just encapsulate the behavior in its own type:

public sealed class OneTimeAssignable<T> where T : class
{
    public T Value
    {
        get
        {
            return mValue;
        }
        set
        {
            if( mValue != null ) throw new InvalidOperationException( "Value can only be assigned once." );

            mValue = value;
        }
    }

    private T mValue;
}

Now you can use it as the backing field for your properties:

class MyClass
{
    private readonly OneTimeAssignable<AnotherClass> mReference = new OneTimeAssignable<AnotherClass>();
    public AnotherClass Reference
    {
        get
        {
            return this.mReference.Value;
        }
        internal set
        {
            this.mReference.Value = value;
        }
    }
}

Right now I have it set to only work on reference types (and assuming you don't want them to ever be set to null), but it's easy enough to modify it to accept value types as well, but requires adding a bool to track whether the property has been set.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...