I am writing a library that other developers in our company will use. A state machine base class has a ReadOnlyCollection<T> of allowed states, etc. Developers need to inherit from this class and set the allowed states.

I want to limit them to initialize the ReadOnlyCollection<T> in the constructor of their derived classes and not be able to modify it later.

If I declare the ReadOnlyCollection<T> as a read-only property in the base class, that does not work since it cannot be modified in the constructor of the derived class.

I imagine this to be a not-so-uncommon scenario. Any elegant way to achieve this short of having developers override the ReadOnlyCollection<T>?

有帮助吗?

解决方案

Don't let them initialize by themselves. Make your base class constructor to take the collection as an argument:

public class BaseClass
{
      protected readonly Collection someObject;
      public BaseClass(Collection object)
      {
            someObject = object
      }
}

So now when the derived class constructor is called it should call base class constructor also with the collection object otherwise it will be a compile time error. This will make sure that the collection is initialized in the constructor and no where else.

public class Derivedclass : BaseClass
{
      public DerivedClass() : base(/*pass the collection object here*/)
      {
      }
}

Still there is a pit fall in this, if you get the reference of a collection, you can still modify the collection by calling Add or remove method of the collection in the derived class only thing is you cant reinitialize if its readonly.

其他提示

Does it have to be a ReadOnlyCollection ? I would go for IEnumerable.

This could be done like this, similar to srsyogesh´s answer:

public abstract class StateMachine
{
    public StateMachine(params States[] allowedStates)
    {
        _allowedStates = allowedStates;
    }

    private readonly IEnumerable<States> _allowedStates;

    public IEnumerable<States> AllowedStates
    {
        get { return _allowedStates; }
    }
}

public class DerivedStateMachine : StateMachine
{
    public DerivedStateMachine()
        : base(States.State1, States.State2)
    {

    }
}

Of course, one could still cast the Property back to an array and change it, but that would be kind of criminal. Depends on your audience. To be more bullet proof, you could, instead of just returning the field, iterate over the contents:

    public IEnumerable<States> AllowedStates
    {
        get
        {
            foreach(var state in _allowedStates)
                yield return state;
        }
    }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top