private static PropertyDescriptorCollection GetPropertiesImpl(object component, Attribute[] attributes, bool noCustomTypeDesc, bool noAttributes)
{
if (component == null)
{
Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
return new PropertyDescriptorCollection(null, true);
}
// We create a sort of pipeline for mucking with metadata. The pipeline
// goes through the following process:
//
// 1. Merge metadata from extenders.
// 2. Allow services to filter the metadata
// 3. If an attribute filter was specified, apply that.
//
// The goal here is speed. We get speed by not copying or
// allocating memory. We do this by allowing each phase of the
// pipeline to cache its data in the object cache. If
// a phase makes a change to the results, this change must cause
// successive phases to recompute their results as well. "Results" is
// always a collection, and the various stages of the pipeline may
// replace or modify this collection (depending on if it's a
// read-only IList or not). It is possible for the orignal
// descriptor or attribute collection to pass through the entire
// pipeline without modification.
//
ICustomTypeDescriptor typeDesc = GetDescriptor(component, noCustomTypeDesc);
ICollection results;
// If we are handed a custom type descriptor we have several choices of action
// we can take. If noCustomTypeDesc is true, it means that the custom type
// descriptor is trying to find a baseline set of properties. In this case
// we should merge in extended properties, but we do not let designers filter
// because we're not done with the property set yet. If noCustomTypeDesc
// is false, we don't do extender properties because the custom type descriptor
// has already added them. In this case, we are doing a final pass so we
// want to apply filtering. Finally, if the incoming object is not a custom
// type descriptor, we do extenders and the filter.
//
if (component is ICustomTypeDescriptor)
{
results = noAttributes ? typeDesc.GetProperties() : typeDesc.GetProperties(attributes);
if (noCustomTypeDesc)
{
ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
if (extDesc != null)
{
ICollection extResults = noAttributes ? extDesc.GetProperties() : extDesc.GetProperties(attributes);
results = PipelineMerge(PIPELINE_PROPERTIES, results, extResults, component, null);
}
}
else
{
results = PipelineFilter(PIPELINE_PROPERTIES, results, component, null);
results = PipelineAttributeFilter(PIPELINE_PROPERTIES, results, attributes, component, null);
}
}
else
{
IDictionary cache = GetCache(component);
results = noAttributes ? typeDesc.GetProperties() : typeDesc.GetProperties(attributes);
results = PipelineInitialize(PIPELINE_PROPERTIES, results, cache);
ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
if (extDesc != null)
{
ICollection extResults = noAttributes ? extDesc.GetProperties() : extDesc.GetProperties(attributes);
results = PipelineMerge(PIPELINE_PROPERTIES, results, extResults, component, cache);
}
results = PipelineFilter(PIPELINE_PROPERTIES, results, component, cache);
results = PipelineAttributeFilter(PIPELINE_PROPERTIES, results, attributes, component, cache);
}
PropertyDescriptorCollection props = results as PropertyDescriptorCollection;
if (props == null)
{
PropertyDescriptor[] propArray = new PropertyDescriptor[results.Count];
results.CopyTo(propArray, 0);
props = new PropertyDescriptorCollection(propArray, true);
}
return props;
}