/// <devdoc> /// 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. /// </devdoc> 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(_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[_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) { Trace("Pipeline : Filter needs to create member list for {0}", instance.GetType().Name); 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.GetString(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.GetString(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.GetString(SR.TypeDescriptorExpectedElementType, typeof(EventDescriptor).FullName)); } cacheValue = new EventDescriptorCollection(eventArray, true); break; default: Debug.Fail("unknown pipeline type"); cacheValue = null; break; } Trace("Pipeline : Filter results being cached for {0}", instance.GetType().Name); FilterCacheItem cacheItem = new FilterCacheItem(componentFilter, cacheValue); cache[_pipelineFilterKeys[pipelineType]] = cacheItem; cache.Remove(_pipelineAttributeFilterKeys[pipelineType]); } return list; }
private static ICollection PipelineFilter(int pipelineType, ICollection members, object instance, IDictionary cache) { bool flag; IComponent component = instance as IComponent; ITypeDescriptorFilterService filterService = null; if (component != null) { ISite site = component.Site; if (site != null) { filterService = site.GetService(typeof(ITypeDescriptorFilterService)) as ITypeDescriptorFilterService; } } IList list = members as ArrayList; if (filterService == null) { return members; } if ((cache != null) && ((list == null) || list.IsReadOnly)) { FilterCacheItem item = cache[_pipelineFilterKeys[pipelineType]] as FilterCacheItem; if ((item != null) && item.IsValid(filterService)) { return item.FilteredMembers; } } OrderedDictionary attributes = new OrderedDictionary(members.Count); switch (pipelineType) { case 0: foreach (Attribute attribute in members) { attributes[attribute.TypeId] = attribute; } flag = filterService.FilterAttributes(component, attributes); break; case 1: case 2: foreach (MemberDescriptor descriptor in members) { string name = descriptor.Name; if (attributes.Contains(name)) { string extenderCollisionSuffix = GetExtenderCollisionSuffix(descriptor); if (extenderCollisionSuffix != null) { attributes[name + extenderCollisionSuffix] = descriptor; } MemberDescriptor member = (MemberDescriptor) attributes[name]; extenderCollisionSuffix = GetExtenderCollisionSuffix(member); if (extenderCollisionSuffix != null) { attributes.Remove(name); attributes[member.Name + extenderCollisionSuffix] = member; } } else { attributes[name] = descriptor; } } if (pipelineType == 1) { flag = filterService.FilterProperties(component, attributes); } else { flag = filterService.FilterEvents(component, attributes); } break; default: flag = false; break; } if ((list == null) || list.IsReadOnly) { list = new ArrayList(attributes.Values); } else { list.Clear(); foreach (object obj2 in attributes.Values) { list.Add(obj2); } } if (flag && (cache != null)) { ICollection is2; switch (pipelineType) { case 0: { Attribute[] array = new Attribute[list.Count]; try { list.CopyTo(array, 0); } catch (InvalidCastException) { throw new ArgumentException(SR.GetString("TypeDescriptorExpectedElementType", new object[] { typeof(Attribute).FullName })); } is2 = new AttributeCollection(array); break; } case 1: { PropertyDescriptor[] descriptorArray = new PropertyDescriptor[list.Count]; try { list.CopyTo(descriptorArray, 0); } catch (InvalidCastException) { throw new ArgumentException(SR.GetString("TypeDescriptorExpectedElementType", new object[] { typeof(PropertyDescriptor).FullName })); } is2 = new PropertyDescriptorCollection(descriptorArray, true); break; } case 2: { EventDescriptor[] descriptorArray2 = new EventDescriptor[list.Count]; try { list.CopyTo(descriptorArray2, 0); } catch (InvalidCastException) { throw new ArgumentException(SR.GetString("TypeDescriptorExpectedElementType", new object[] { typeof(EventDescriptor).FullName })); } is2 = new EventDescriptorCollection(descriptorArray2, true); break; } default: is2 = null; break; } FilterCacheItem item2 = new FilterCacheItem(filterService, is2); cache[_pipelineFilterKeys[pipelineType]] = item2; cache.Remove(_pipelineAttributeFilterKeys[pipelineType]); } return list; }