Open sandboxFocusImprove this doc

Enumerating Child Objects (Visitor)

After you have Annotating an Object Model for Parent/Child Relationships (Aggregatable), you will want to make use of it.

Both the ChildAttribute and ParentAttribute can be used to declare parent-child relationships for other patterns such as Undo/Redo (RecordableAttribute) or threading models (ImmutableAttribute, FreezableAttribute, ...).

You can also use the Aggregatable pattern from your own code. The functionalities of this pattern are exposed by the IAggregatable interface, which all aggregatable object automatically implement. This interface allows you to execute a Visitor method against all child objects of a parent.

In the following example, we see how to implement recursive validation for an object model. We will assume that the InvoiceLine and Address line implement an IValidatable interface.

To enumerate all child objects of a parent:

  1. Cast the parent object to the IAggregatable interface.

    var invoice = new Invoice();
    IAggregatable aggregatable = (IAggregatable) invoice;
    
    Note

    The IAggregatable interface will be injected into the Invoice class after compilation. Tools that are not aware of PostSharp may incorrectly report that the Invoice class does not implement the IAggregatable interface. Instead of using the cast operator, you can also use the Cast<TSource, TTarget>(TSource) method. This method is faster and safer than the cast operator because it is verified and compiled by PostSharp at build time.


    Note

    If you are attempting to access IAggregatable members on either AdvisableCollection<T> or AdvisableDictionary<TKey, TValue> you will not be able to use the cast operator or the Cast<TSource, TTarget>(TSource) method. Instead, you will have to use the QueryInterface<T>(object, bool) extension method.

  2. Invoke the VisitChildren(ChildVisitor, ChildVisitorOptions, object) method and pass a delegate to the method to be executed.

    var invoice = new Invoice();
    IAggregatable aggregatable = invoice.QueryInterface<IAggregatable>();
    int errors = 0;
    bool isValid = aggregatable.VisitChildren( (child, childInfo) =>
            {
    	        var validatable = child as IValidatable;
    	        if (validatable != null)
    	        {
    		        if ( !validatable.Validate() )
                  errors++;
    	        }
              return true;
            });
    
    Note

    The visitor must return a true to continue the enumeration and false to stop the enumeration.

See Also

Reference

AggregatableAttribute
ParentAttribute
ChildAttribute
IAggregatable
VisitChildren(ChildVisitor, ChildVisitorOptions, object)
Cast<TSource, TTarget>(TSource)
QueryInterface<T>(object, bool)