System.ComponentModel.TypeDescriptor.PipelineFilter C# (CSharp) Method

PipelineFilter() private static method

Metdata filtering is the third stage of our pipeline. In this stage we check to see if the given object is a sited component that provides the ITypeDescriptorFilterService object. If it does, we allow the TDS to filter the metadata. This will use the cache, if available, to store filtered metdata.
private static PipelineFilter ( int pipelineType, ICollection members, object instance, IDictionary cache ) : ICollection
pipelineType int
members ICollection
instance object
cache IDictionary
return ICollection
        private static ICollection PipelineFilter(int pipelineType, ICollection members, object instance, IDictionary cache)
        {
            IComponent component = instance as IComponent;
            ITypeDescriptorFilterService componentFilter = null;

            if (component != null)
            {
                ISite site = component.Site;
                if (site != null)
                {
                    componentFilter = site.GetService(typeof(ITypeDescriptorFilterService)) as ITypeDescriptorFilterService;
                }
            }

            // If we have no filter, there is nothing for us to do.
            //
            IList list = members as ArrayList;

            if (componentFilter == null)
            {
                Debug.Assert(cache == null || list == null || !cache.Contains(s_pipelineFilterKeys[pipelineType]), "Earlier pipeline stage should have removed our cache");
                return members;
            }

            // Now, check our cache.  The cache state is only valid
            // if the data coming into us is read-only.  If it is read-write,
            // that means something higher in the pipeline has already changed
            // it so we must recompute anyway.
            //
            if (cache != null && (list == null || list.IsReadOnly))
            {
                FilterCacheItem cacheItem = cache[s_pipelineFilterKeys[pipelineType]] as FilterCacheItem;
                if (cacheItem != null && cacheItem.IsValid(componentFilter))
                {
                    return cacheItem.FilteredMembers;
                }
            }

            // Cache either is dirty or doesn't exist.  Re-filter the members.
            // We need to build an IDictionary of key->value pairs and invoke
            // Filter* on the filter service.
            //
            OrderedDictionary filterTable = new OrderedDictionary(members.Count);
            bool cacheResults;

            switch (pipelineType)
            {
                case PIPELINE_ATTRIBUTES:
                    foreach (Attribute attr in members)
                    {
                        filterTable[attr.TypeId] = attr;
                    }
                    cacheResults = componentFilter.FilterAttributes(component, filterTable);
                    break;

                case PIPELINE_PROPERTIES:
                case PIPELINE_EVENTS:
                    foreach (MemberDescriptor desc in members)
                    {
                        string descName = desc.Name;
                        // We must handle the case of duplicate property names
                        // because extender providers can provide any arbitrary
                        // name.  Our rule for this is simple:  If we find a
                        // duplicate name, resolve it back to the extender
                        // provider that offered it and append "_" + the
                        // provider name.  If the provider has no name,
                        // then append the object hash code.
                        //
                        if (filterTable.Contains(descName))
                        {
                            // First, handle the new property.  Because
                            // of the order in which we added extended
                            // properties earlier in the pipeline, we can be 
                            // sure that the new property is an extender.  We
                            // cannot be sure that the existing property
                            // in the table is an extender, so we will 
                            // have to check.
                            //
                            string suffix = GetExtenderCollisionSuffix(desc);
                            Debug.Assert(suffix != null, "Name collision with non-extender property.");
                            if (suffix != null)
                            {
                                filterTable[descName + suffix] = desc;
                            }

                            // Now, handle the original property.
                            //
                            MemberDescriptor origDesc = (MemberDescriptor)filterTable[descName];
                            suffix = GetExtenderCollisionSuffix(origDesc);
                            if (suffix != null)
                            {
                                filterTable.Remove(descName);
                                filterTable[origDesc.Name + suffix] = origDesc;
                            }
                        }
                        else
                        {
                            filterTable[descName] = desc;
                        }
                    }
                    if (pipelineType == PIPELINE_PROPERTIES)
                    {
                        cacheResults = componentFilter.FilterProperties(component, filterTable);
                    }
                    else
                    {
                        cacheResults = componentFilter.FilterEvents(component, filterTable);
                    }
                    break;

                default:
                    Debug.Fail("unknown pipeline type");
                    cacheResults = false;
                    break;
            }

            // See if we can re-use the IList were were passed.  If we can,
            // it is more efficient to re-use its slots than to generate new ones.
            //
            if (list == null || list.IsReadOnly)
            {
                list = new ArrayList(filterTable.Values);
            }
            else
            {
                list.Clear();
                foreach (object obj in filterTable.Values)
                {
                    list.Add(obj);
                }
            }

            // Component filter has requested that we cache these
            // new changes.  We store them as a correctly typed collection
            // so on successive invocations we can simply return.  Note that
            // we always return the IList so that successive stages in the
            // pipeline can modify it.
            //
            if (cacheResults && cache != null)
            {
                ICollection cacheValue;

                switch (pipelineType)
                {
                    case PIPELINE_ATTRIBUTES:
                        Attribute[] attrArray = new Attribute[list.Count];
                        try
                        {
                            list.CopyTo(attrArray, 0);
                        }
                        catch (InvalidCastException)
                        {
                            throw new ArgumentException(SR.GetResourceString(SR.TypeDescriptorExpectedElementType, typeof(Attribute).FullName));
                        }
                        cacheValue = new AttributeCollection(attrArray);
                        break;

                    case PIPELINE_PROPERTIES:
                        PropertyDescriptor[] propArray = new PropertyDescriptor[list.Count];
                        try
                        {
                            list.CopyTo(propArray, 0);
                        }
                        catch (InvalidCastException)
                        {
                            throw new ArgumentException(SR.GetResourceString(SR.TypeDescriptorExpectedElementType, typeof(PropertyDescriptor).FullName));
                        }
                        cacheValue = new PropertyDescriptorCollection(propArray, true);
                        break;

                    case PIPELINE_EVENTS:
                        EventDescriptor[] eventArray = new EventDescriptor[list.Count];
                        try
                        {
                            list.CopyTo(eventArray, 0);
                        }
                        catch (InvalidCastException)
                        {
                            throw new ArgumentException(SR.GetResourceString(SR.TypeDescriptorExpectedElementType, typeof(EventDescriptor).FullName));
                        }
                        cacheValue = new EventDescriptorCollection(eventArray, true);
                        break;

                    default:
                        Debug.Fail("unknown pipeline type");
                        cacheValue = null;
                        break;
                }

                FilterCacheItem cacheItem = new FilterCacheItem(componentFilter, cacheValue);
                cache[s_pipelineFilterKeys[pipelineType]] = cacheItem;
                cache.Remove(s_pipelineAttributeFilterKeys[pipelineType]);
            }

            return list;
        }