/// <summary> /// Adds a composite event to the state machine. A composite event is triggered when all /// off the required events have been raised. Note that required events cannot be in the initial /// state since it would cause extra instances of the state machine to be created /// </summary> /// <param name="propertyExpression">The composite event</param> /// <param name="trackingPropertyExpression">The property in the instance used to track the state of the composite event</param> /// <param name="events">The events that must be raised before the composite event is raised</param> protected void Event(Expression <Func <Event> > propertyExpression, Expression <Func <TInstance, CompositeEventStatus> > trackingPropertyExpression, params Event[] events) { if (events == null) { throw new ArgumentNullException("events"); } if (events.Length > 31) { throw new ArgumentException("No more than 31 events can be combined into a single event"); } if (events.Length == 0) { throw new ArgumentException("At least one event must be specified for a composite event"); } if (events.Any(x => x == null)) { throw new ArgumentException("One or more events specified has not yet been initialized"); } PropertyInfo eventProperty = propertyExpression.GetPropertyInfo(); PropertyInfo trackingPropertyInfo = trackingPropertyExpression.GetPropertyInfo(); string name = eventProperty.Name; var @event = new SimpleEvent(name); eventProperty.SetValue(this, @event); _eventCache[name] = new StateMachineEvent <TInstance>(@event); var complete = new CompositeEventStatus(Enumerable.Range(0, events.Length) .Aggregate(0, (current, x) => current | (1 << x))); for (int i = 0; i < events.Length; i++) { int flag = 1 << i; var activity = new CompositeEventActivity <TInstance>(trackingPropertyInfo, flag, complete, (consumer, instance) => ((StateMachine <TInstance>) this).RaiseEvent(consumer, instance, @event)); foreach (var state in _stateCache.Where(x => !Equals(x, Initial))) { During(state, When(events[i]) .Then(() => activity)); } } }
void CompositeEvent(Expression <Func <Event> > propertyExpression, CompositeEventStatusAccessor <TInstance> accessor, CompositeEventOptions options, Event[] events) { if (events == null) { throw new ArgumentNullException(nameof(events)); } if (events.Length > 31) { throw new ArgumentException("No more than 31 events can be combined into a single event"); } if (events.Length == 0) { throw new ArgumentException("At least one event must be specified for a composite event"); } if (events.Any(x => x == null)) { throw new ArgumentException("One or more events specified has not yet been initialized"); } PropertyInfo eventProperty = propertyExpression.GetPropertyInfo(); string name = eventProperty.Name; var @event = new TriggerEvent(name); eventProperty.SetValue(this, @event); _eventCache[name] = new StateMachineEvent <TInstance>(@event, false); var complete = new CompositeEventStatus(Enumerable.Range(0, events.Length) .Aggregate(0, (current, x) => current | (1 << x))); for (int i = 0; i < events.Length; i++) { int flag = 1 << i; var activity = new CompositeEventActivity <TInstance>(accessor, flag, complete, @event); Func <State <TInstance>, bool> filter = x => options.HasFlag(CompositeEventOptions.IncludeInitial) || !Equals(x, Initial); foreach (var state in _stateCache.Values.Where(filter)) { During(state, When(events[i]) .Execute(x => activity)); } } }