/// ObjectIdFilter.cs Copyright (c) 2012 Tony Tanzillo
/// <summary>
///
/// ObjectIdFilter class
///
/// Used to efficiently do simple and complex filtering
/// of ObjectIds based on associated managed wrapper types.
///
/// This class helps to simplify Linq code that performs
/// complex filtering of ObjectIds based on the associated
/// managed wrapper type of each ObjectId.
///
/// An example:
///
/// BlockTableRecord btr = //.. (open some BlockTableRecord)
///
/// // Get a filter that includes only entities
/// // whose managed wrappers are derived from
/// // AutoDesk.AutoCAD.DatabaseServices.Curve:
///
/// ObjectIdFilter curveFilter = new ObjectIdFilter<Curve>();
///
/// // Get an object that enumerates the ObjectIds
/// // of all Curve objects in the BlockTableRecord:
///
/// var curveIds = btr.Cast<ObjectId>().Where( curveFilter.Predicate );
///
/// // In AutoCAD 2013 or later, the above line can
/// // be reduced to:
///
/// var curveIds = btr.Where( curveFilter.Predicate );
///
/// // Additionally, in all AutoCAD releases, the
/// // GetObjectIds() method of the ObjectIdFilter
/// // class can be used to do the equivalent:
///
/// var curveIds = curveFilter.GetObjectIds( btr );
///
/// Complex Filtering Criteria:
///
/// The ObjectIdFilter class as used above offers little
/// advantages over explicit testing of each ObjectId's
/// ObjectClass property with standard Linq methods, but
/// the ObjectIdFilter was actually created to simplify
/// a more-complicated problem, which involves filtering
/// against multiple types, both related and unrelated;
/// filtering against types derived from multiple types;
/// and being more-selective, by explicitly including or
/// excluding certain specified types individually.
///
/// For example, the following filter will include only
/// the ObjectIds of Lines, Arcs, and Polylines:
///
/// var curveSubSetFilter = new ObjectIdFilter(
/// typeof( Line ),
/// typeof( Arc ),
/// typeof( Polyline )
/// );
///
/// Overriding Criteria:
///
/// The ObjectIdFilter allows the programmer to override
/// criteria that includes or excludes all types derived
/// from a given type, to specifically include or exclude
/// one or more derived types, on a type-by-type basis.
///
/// This example includes all types of Dimensions except
/// for OrdinateDimensions using an overriding criteria:
///
/// // Define an ObjectIdFilter with the sole criteria
/// // that includes all types derived from Dimension:
///
/// ObjectIdFilter dimfilter = new ObjectIdFilter<Dimension>();
///
/// // Override the criteria that includes all types
/// // derived from Dimension, to exclude Ordinate
/// // dimensions:
///
/// dimfilter[typeof(OrdinateDimension)] = false;
///
/// Overriding criteria can also override other
/// overriding criteria.
///
/// The next example uses an override on a filter that
/// includes all Curve types, to exclude Splines and all
/// types derived from Spline, and then overrides that
/// criteria to specifically include Helixes, which are
/// derived from Spline:
///
/// var myFilter = new ObjectIdFilter<Curve>();
///
/// // allow/disallow types derived from those
/// // types that are explicitly-included or
/// // excluded:
///
/// myFilter.ExactMatch = false;
///
/// // Add an override that excludes Splines and
/// // all types derived from Spline:
///
/// myFilter[typeof(Spline)] = false;
///
/// // we then override the above override that excludes
/// // Spline and all derived types, to specifically
/// // include Helixes (which are derived from Spline):
///
/// myFilter[typeof(Helix)] = true;
///
/// The above example defines a filter that will
/// include all Curves, including Helixes, but
/// not Splines or any other type derived from
/// Spline. and is functionally-equivalent to
/// this delegate:
///
/// bool IsCurveOrNotSplineExceptHelix( ObjectId id )
/// {
/// RXClass curveClass = RXClass.GetClass(typeof(Curve));
/// RXClass splineClass = RXClass.GetClass(typeof(Spline));
/// RXClass helixClass = RXClass.GetClass(typeof(Helix));
///
/// RXClass objectClass = id.ObjectClass;
///
/// return objectClass.IsDerivedFrom( curveClass )
/// && ( ! objectClass.IsDerivedFrom( splineClass )
/// || objectClass.IsDerivedFrom( helixClass ) );
/// }
///
/// As unrealistic as it is, the above example serves to
/// demonstrate the degree of granularity that can easily
/// be achieved using the ObjectIdFilter with overriding
/// criteria.
///
/// This next example uses two overriding criteria to
/// include all Curve objects EXCEPT XLines and Rays:
///
/// var myFilter = new ObjectIdFilter<Curve>();
/// myFilter[typeof(XLine)] = false;
/// myFilter[typeof(Ray)] = false;
///
/// The predicate generated by ObjectIdFilter in the
/// above example does what this delegate does:
///
/// bool IsCurveExceptXLineOrRay( ObjectId id )
/// {
/// RXClass curveClass = RXClass.GetClass(typeof(Curve));
/// RXClass rayClass = RXClass.GetClass(typeof(Ray));
/// RXClass xlineClass = RXClass.GetClass(typeof(XLine));
///
/// RXClass objectClass = id.ObjectClass;
/// return objectClass.IsDerivedFrom( curveClass )
/// && objectClass != rayClass
/// && objectClass != xlineClass;
/// }
///
/// Note that the equivalent predicates are relatively-complex
/// in contrast to the ObjectIdFilter, and yet ObjectIdFilter
/// is as fast, and in some cases faster than the direct use
/// of hand-coded predicates when used with the Linq Where()
/// function.
///
/// Performance:
///
/// The performance of ObjectIdFilter is comparable to the
/// performance of explicit, hand-coded predicates in most
/// use cases, and can be faster in some, mainly those that
/// involve expensive predicates. The basic purpose of this
/// class is not to out-perform other methods of filtering,
/// but more for the purpose of simplifying the writing of
/// code that defines the criteria, and to support dynamic
/// composition of filters based on criteria that is unknown
/// at compile-time, and would otherwise require complicated
/// means to achieve.
///
/// </summary>