Implement mono_gc_alloc_fixed on Boehm to be uncollectable. This matches SGen behavio...
[mono.git] / mcs / class / referencesource / System / compmod / system / componentmodel / TypeDescriptor.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="TypeDescriptor.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>                                                                
5 //------------------------------------------------------------------------------
6
7 /*
8  */
9 namespace System.ComponentModel 
10 {
11     using System.Runtime.Serialization.Formatters;
12     using System.Threading;
13     using System.Runtime.Remoting.Activation;
14     using System.Runtime.InteropServices;
15     using System.Diagnostics;
16     using System;
17     using CodeAccessPermission = System.Security.CodeAccessPermission;
18     using System.Security;
19     using System.Security.Permissions;
20     using System.Collections;
21     using System.Collections.Specialized;
22     using System.Globalization;
23     using System.IO;
24     using System.Reflection;
25     using Microsoft.Win32;
26     using System.ComponentModel.Design;
27     using System.Diagnostics.CodeAnalysis;
28     using System.Runtime.Versioning;
29
30     /// <devdoc>
31     ///    Provides information about the properties and events
32     ///    for a component. This class cannot be inherited.
33     /// </devdoc>
34     [HostProtection(SharedState = true)]
35     public sealed class TypeDescriptor 
36     {
37         // Note: this is initialized at class load because we 
38         // lock on it for thread safety.  It is used from nearly
39         // every call to this class, so it will be created soon after
40         // class load anyway.
41         private static WeakHashtable _providerTable     = new WeakHashtable();  // mapping of type or object hash to a provider list
42         private static Hashtable     _providerTypeTable = new Hashtable();      // A direct mapping from type to provider.
43         private static volatile Hashtable _defaultProviders  = new Hashtable();      // A table of type -> default provider to track DefaultTypeDescriptionProviderAttributes.
44         private static volatile WeakHashtable _associationTable;
45         private static int           _metadataVersion;                          // a version stamp for our metadata.  Used by property descriptors to know when to rebuild
46                                                                                 // attributes.
47
48         
49         // This is an index that we use to create a unique name for a property in the
50         // event of a name collision.  The only time we should use this is when
51         // a name collision happened on an extender property that has no site or
52         // no name on its site.  Should be very rare.
53         private static int _collisionIndex;
54
55         private static BooleanSwitch TraceDescriptor = new BooleanSwitch("TypeDescriptor", "Debug TypeDescriptor.");
56
57         #if DEBUG
58         private static BooleanSwitch EnableValidation = new BooleanSwitch("EnableValidation", "Enable type descriptor Whidbey->RTM validation");
59         #endif
60
61         // For each stage of our filtering pipeline, the pipeline needs to know
62         // what it is filtering.
63         private const int PIPELINE_ATTRIBUTES = 0x00;
64         private const int PIPELINE_PROPERTIES = 0x01;
65         private const int PIPELINE_EVENTS = 0x02;
66
67         // And each stage of the pipeline needs to have its own
68         // keys for its cache table.  We use guids because they
69         // are unique and fast to compare.  The order for each of
70         // these keys must match the Id's of the filter type above.
71         private static readonly Guid[] _pipelineInitializeKeys = new Guid[]
72         {
73             Guid.NewGuid(), // attributes
74             Guid.NewGuid(), // properties
75             Guid.NewGuid()  // events
76         };
77
78         private static readonly Guid[] _pipelineMergeKeys = new Guid[]
79         {
80             Guid.NewGuid(), // attributes
81             Guid.NewGuid(), // properties
82             Guid.NewGuid()  // events
83         };
84
85         private static readonly Guid[] _pipelineFilterKeys = new Guid[]
86         {
87             Guid.NewGuid(), // attributes
88             Guid.NewGuid(), // properties
89             Guid.NewGuid()  // events
90         };
91
92         private static readonly Guid[] _pipelineAttributeFilterKeys = new Guid[]
93         {
94             Guid.NewGuid(), // attributes
95             Guid.NewGuid(), // properties
96             Guid.NewGuid()  // events
97         };
98         
99         private static object _internalSyncObject = new object();
100
101         private TypeDescriptor() 
102         {
103         }
104
105         /// <internalonly/>
106         /// <devdoc>
107         /// </devdoc>
108         [Obsolete("This property has been deprecated.  Use a type description provider to supply type information for COM types instead.  http://go.microsoft.com/fwlink/?linkid=14202")]
109         public static IComNativeDescriptorHandler ComNativeDescriptorHandler 
110         {
111             [PermissionSetAttribute(SecurityAction.LinkDemand, Name="FullTrust")]
112             get 
113             {
114                 TypeDescriptionNode node = NodeFor(ComObjectType);
115                 ComNativeDescriptionProvider provider = null;
116                 
117                 do
118                 {
119                     provider = node.Provider as ComNativeDescriptionProvider;
120                     node = node.Next;
121                 }
122                 while(node != null && provider == null);
123
124                 if (provider != null)
125                 {
126                     return provider.Handler;
127                 }
128
129                 return null;
130             }
131             [PermissionSetAttribute(SecurityAction.LinkDemand, Name="FullTrust")]
132             set 
133             {
134                 TypeDescriptionNode node = NodeFor(ComObjectType);
135
136                 while (node != null && !(node.Provider is ComNativeDescriptionProvider))
137                 {
138                     node = node.Next;
139                 }
140
141                 if (node == null)
142                 {
143                     AddProvider(new ComNativeDescriptionProvider(value), ComObjectType);
144                 }
145                 else
146                 {
147                     ComNativeDescriptionProvider provider = (ComNativeDescriptionProvider)node.Provider;
148                     provider.Handler = value;
149                 }
150             }
151         }
152
153
154         /// <devdoc>
155         ///     This property returns a Type object that can be passed to the various 
156         ///     AddProvider methods to define a type description provider for COM types.
157         /// </devdoc>
158         [EditorBrowsable(EditorBrowsableState.Advanced)]
159         public static Type ComObjectType
160         {
161             get
162             {
163                 return typeof(TypeDescriptorComObject);
164             }
165         }
166
167         /// <devdoc>
168         ///     This property returns a Type object that can be passed to the various 
169         ///     AddProvider methods to define a type description provider for interface types.
170         /// </devdoc>
171         [EditorBrowsable(EditorBrowsableState.Advanced)]
172         public static Type InterfaceType
173         {
174             get
175             {
176                 return typeof(TypeDescriptorInterface);
177             }
178         }
179
180         /// <devdoc>
181         ///     This value increments each time someone refreshes or changes metadata.
182         /// </devdoc>
183         internal static int MetadataVersion {
184             get {
185                 return _metadataVersion;
186             }
187         }
188
189         /// <include file='doc\TypeDescriptor.uex' path='docs/doc[@for="TypeDescriptor.Refreshed"]/*' />
190         /// <devdoc>
191         ///    Occurs when Refreshed is raised for a component.
192         /// </devdoc>
193         public static event RefreshEventHandler Refreshed; 
194
195         /// <devdoc>
196         ///     The AddAttributes method allows you to add class-level attributes for a 
197         ///     type or an instance.  This method simply implements a type description provider 
198         ///     that merges the provided attributes with the attributes that already exist on 
199         ///     the class.  This is a short cut for such a behavior.  Adding additional 
200         ///     attributes is common need for applications using the Windows Forms property 
201         ///     window.  The return value form AddAttributes is the TypeDescriptionProvider 
202         ///     that was used to add the attributes.  This provider can later be passed to 
203         ///     RemoveProvider if the added attributes are no longer needed.
204         /// </devdoc>
205         [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
206         [EditorBrowsable(EditorBrowsableState.Advanced)]
207         public static TypeDescriptionProvider AddAttributes(Type type, params Attribute[] attributes) {
208
209             if (type == null) {
210                 throw new ArgumentNullException("type");
211             }
212
213             if (attributes == null) {
214                 throw new ArgumentNullException("attributes");
215             }
216
217             TypeDescriptionProvider existingProvider = GetProvider(type);
218             TypeDescriptionProvider provider = new AttributeProvider(existingProvider, attributes);
219             TypeDescriptor.AddProvider(provider, type);
220             return provider;
221         }
222
223         /// <devdoc>
224         ///     The AddAttributes method allows you to add class-level attributes for a 
225         ///     type or an instance.  This method simply implements a type description provider 
226         ///     that merges the provided attributes with the attributes that already exist on 
227         ///     the class.  This is a short cut for such a behavior.  Adding additional 
228         ///     attributes is common need for applications using the Windows Forms property 
229         ///     window.  The return value form AddAttributes is the TypeDescriptionProvider 
230         ///     that was used to add the attributes.  This provider can later be passed to 
231         ///     RemoveProvider if the added attributes are no longer needed.
232         /// </devdoc>
233         [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
234         [EditorBrowsable(EditorBrowsableState.Advanced)]
235         public static TypeDescriptionProvider AddAttributes(object instance, params Attribute[] attributes) {
236             
237             if (instance == null) {
238                 throw new ArgumentNullException("instance");
239             }
240
241             if (attributes == null) {
242                 throw new ArgumentNullException("attributes");
243             }
244
245             TypeDescriptionProvider existingProvider = GetProvider(instance);
246             TypeDescriptionProvider provider = new AttributeProvider(existingProvider, attributes);
247             TypeDescriptor.AddProvider(provider, instance);
248             return provider;
249         }
250
251         /// <internalonly/>
252         /// <devdoc>
253         ///     Adds an editor table for the given editor base type.
254         ///     ypically, editors are specified as metadata on an object. If no metadata for a
255         ///     equested editor base type can be found on an object, however, the
256         ///     ypeDescriptor will search an editor
257         ///     able for the editor type, if one can be found.
258         /// </devdoc>
259         [EditorBrowsable(EditorBrowsableState.Advanced)]
260         public static void AddEditorTable(Type editorBaseType, Hashtable table) 
261         {
262             ReflectTypeDescriptionProvider.AddEditorTable(editorBaseType, table);
263         }
264
265         /// <devdoc>
266         ///     Adds a type description provider that will be called on to provide 
267         ///     type and instance information for any object that is of, or a subtype 
268         ///     of, the provided type.  Type can be any type, including interfaces.  
269         ///     For example, to provide custom type and instance information for all 
270         ///     components, you would pass typeof(IComponent).  Passing typeof(object) 
271         ///     will cause the provider to be called to provide type information for 
272         ///     all types.
273         /// </devdoc>
274         [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
275         [EditorBrowsable(EditorBrowsableState.Advanced)]
276         public static void AddProvider(TypeDescriptionProvider provider, Type type)
277         {
278             if (provider == null)
279             {
280                 throw new ArgumentNullException("provider");
281             }
282
283             if (type == null)
284             {
285                 throw new ArgumentNullException("type");
286             }
287
288             lock(_providerTable)
289             {
290                 // Get the root node, hook it up, and stuff it back into
291                 // the provider cache.
292                 TypeDescriptionNode node = NodeFor(type, true);
293                 TypeDescriptionNode head = new TypeDescriptionNode(provider);
294                 head.Next = node;
295                 _providerTable[type] = head;
296                 _providerTypeTable.Clear();
297             }
298
299             Refresh(type);
300         }
301
302         /// <devdoc>
303         ///     Adds a type description provider that will be called on to provide 
304         ///     type information for a single object instance.  A provider added 
305         ///     using this method will never have its CreateInstance method called 
306         ///     because the instance already exists.  This method does not prevent 
307         ///     the object from finalizing.
308         /// </devdoc>
309         [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
310         [EditorBrowsable(EditorBrowsableState.Advanced)]
311         public static void AddProvider(TypeDescriptionProvider provider, object instance)
312         {
313             if (provider == null)
314             {
315                 throw new ArgumentNullException("provider");
316             }
317
318             if (instance == null)
319             {
320                 throw new ArgumentNullException("instance");
321             }
322             bool refreshNeeded;
323
324             // Get the root node, hook it up, and stuff it back into
325             // the provider cache.
326             lock(_providerTable)
327             {
328                 refreshNeeded = _providerTable.ContainsKey(instance);
329                 TypeDescriptionNode node = NodeFor(instance, true);
330                 TypeDescriptionNode head = new TypeDescriptionNode(provider);
331                 head.Next = node;
332                 _providerTable.SetWeak(instance, head);
333                 _providerTypeTable.Clear();
334             }
335
336             if (refreshNeeded)
337             {
338                 Refresh(instance, false);
339             }
340         }
341
342         /// <devdoc>
343         ///     Adds a type description provider that will be called on to provide 
344         ///     type and instance information for any object that is of, or a subtype 
345         ///     of, the provided type.  Type can be any type, including interfaces.  
346         ///     For example, to provide custom type and instance information for all 
347         ///     components, you would pass typeof(IComponent).  Passing typeof(object) 
348         ///     will cause the provider to be called to provide type information for 
349         ///     all types.
350         ///     
351         ///     This method can be called from partially trusted code. If 
352         ///     <see cref="TypeDescriptorPermissionFlags.RestrictedRegistrationAccess"/>
353         ///     is defined, the caller can register a provider for the specified type 
354         ///     if it's also partially trusted.
355         /// </devdoc>
356         [EditorBrowsable(EditorBrowsableState.Advanced)]
357         public static void AddProviderTransparent(TypeDescriptionProvider provider, Type type)
358         {
359             if (provider == null)
360             {
361                 throw new ArgumentNullException("provider");
362             }
363
364             if (type == null)
365             {
366                 throw new ArgumentNullException("type");
367             }
368 #if FEATURE_MONO_CAS
369             PermissionSet typeDescriptorPermission = new PermissionSet(PermissionState.None);
370             typeDescriptorPermission.AddPermission(new TypeDescriptorPermission(TypeDescriptorPermissionFlags.RestrictedRegistrationAccess));
371
372             PermissionSet targetPermissions = type.Assembly.PermissionSet;
373             targetPermissions = targetPermissions.Union(typeDescriptorPermission);
374
375             targetPermissions.Demand();
376 #endif
377             AddProvider(provider, type);
378         }
379
380         /// <devdoc>
381         ///     Adds a type description provider that will be called on to provide 
382         ///     type information for a single object instance.  A provider added 
383         ///     using this method will never have its CreateInstance method called 
384         ///     because the instance already exists.  This method does not prevent 
385         ///     the object from finalizing.
386         ///     
387         ///     This method can be called from partially trusted code. If 
388         ///     <see cref="TypeDescriptorPermissionFlags.RestrictedRegistrationAccess"/>
389         ///     is defined, the caller can register a provider for the specified instance 
390         ///     if its type is also partially trusted.
391         /// </devdoc>
392         [EditorBrowsable(EditorBrowsableState.Advanced)]
393         public static void AddProviderTransparent(TypeDescriptionProvider provider, object instance)
394         {
395             if (provider == null)
396             {
397                 throw new ArgumentNullException("provider");
398             }
399
400             if (instance == null)
401             {
402                 throw new ArgumentNullException("instance");
403             }
404 #if FEATURE_MONO_CAS
405             Type type = instance.GetType();
406
407             PermissionSet typeDescriptorPermission = new PermissionSet(PermissionState.None);
408             typeDescriptorPermission.AddPermission(new TypeDescriptorPermission(TypeDescriptorPermissionFlags.RestrictedRegistrationAccess));
409
410             PermissionSet targetPermissions = type.Assembly.PermissionSet;
411             targetPermissions = targetPermissions.Union(typeDescriptorPermission);
412
413             targetPermissions.Demand();
414 #endif
415             AddProvider(provider, instance);
416         }
417
418         /// <devdoc>
419         ///     This method verifies that we have checked for the presence
420         ///     of a default type description provider attribute for the
421         ///     given type.
422         /// </devdoc>
423         //See security note below
424         [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")]
425         private static void CheckDefaultProvider(Type type)
426         {
427             if (_defaultProviders == null)
428             {
429                 lock (_internalSyncObject)
430                 {
431                     if (_defaultProviders == null)
432                     {
433                         _defaultProviders = new Hashtable();
434                     }
435                 }
436             }
437
438             if (_defaultProviders.ContainsKey(type))
439             {
440                 return;
441             }
442
443             lock (_internalSyncObject)
444             {
445                 if (_defaultProviders.ContainsKey(type))
446                 {
447                     return;
448                 }
449
450                 // Immediately clear this.  If we find a default provider
451                 // and it starts messing around with type information, 
452                 // this could infinitely recurse.
453                 //
454                 _defaultProviders[type] = null;
455             }
456
457             // Always use core reflection when checking for
458             // the default provider attribute.  If there is a
459             // provider, we probably don't want to build up our
460             // own cache state against the type.  There shouldn't be
461             // more than one of these, but walk anyway.  Walk in 
462             // reverse order so that the most derived takes precidence.
463             //
464             object[] attrs = type.GetCustomAttributes(typeof(TypeDescriptionProviderAttribute), false);
465             bool providerAdded = false;
466             for (int idx = attrs.Length - 1; idx >= 0; idx--)
467             {
468                 TypeDescriptionProviderAttribute pa = (TypeDescriptionProviderAttribute)attrs[idx];
469                 Type providerType = Type.GetType(pa.TypeName);
470                 if (providerType != null && typeof(TypeDescriptionProvider).IsAssignableFrom(providerType))
471                 {
472                     TypeDescriptionProvider prov;
473
474                     // Security Note: TypeDescriptionProviders are similar to TypeConverters and UITypeEditors in the
475                     // sense that they provide a public API while not necessarily being public themselves. As such,
476                     // we need to allow instantiation of internal TypeDescriptionProviders. See the thread attached
477                     // to VSWhidbey #500522 for a more detailed discussion.
478 #if FEATURE_MONO_CAS
479                     IntSecurity.FullReflection.Assert();
480                     try {
481 #endif
482                         prov = (TypeDescriptionProvider)Activator.CreateInstance(providerType);
483 #if FEATURE_MONO_CAS
484                     }
485                     finally {
486                         CodeAccessPermission.RevertAssert();
487                     }
488 #endif
489                     Trace("Providers : Default provider found : {0}", providerType.Name);
490                     AddProvider(prov, type);
491                     providerAdded = true;
492                 }
493             }
494
495             // If we did not add a provider, check the base class.  
496             if (!providerAdded) {
497                 Type baseType = type.BaseType;
498                 if (baseType != null && baseType != type) {
499                     CheckDefaultProvider(baseType);
500                 }    
501             }
502         }
503
504         /// <devdoc>
505         ///     The CreateAssocation method creates an association between two objects.  
506         ///     Once an association is created, a designer or other filtering mechanism 
507         ///     can add properties that route to either object into the primary object's 
508         ///     property set.  When a property invocation is made against the primary 
509         ///     object, GetAssocation will be called to resolve the actual object 
510         ///     instance that is related to its type parameter.  
511         /// </devdoc>
512         [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
513         [EditorBrowsable(EditorBrowsableState.Advanced)]
514         public static void CreateAssociation(object primary, object secondary)
515         {
516             if (primary == null)
517             {
518                 throw new ArgumentNullException("primary");
519             }
520         
521             if (secondary == null)
522             {
523                 throw new ArgumentNullException("secondary");
524             }
525
526             if (primary == secondary)
527             {
528                 throw new ArgumentException(SR.GetString(SR.TypeDescriptorSameAssociation));
529             }
530
531             if (_associationTable == null)
532             {
533                 lock (_internalSyncObject)
534                 {
535                     if (_associationTable == null)
536                     {
537                         _associationTable = new WeakHashtable();
538                     }
539                 }
540             }
541
542             IList associations = (IList)_associationTable[primary];
543
544             if (associations == null)
545             {
546                 lock (_associationTable)
547                 {
548                     associations = (IList)_associationTable[primary];
549                     if (associations == null)
550                     {
551                         associations = new ArrayList(4);
552                         _associationTable.SetWeak(primary, associations);
553                     }
554                 }
555             }
556             else 
557             {
558                 for (int idx = associations.Count - 1; idx >= 0; idx--)
559                 {
560                     WeakReference r = (WeakReference)associations[idx];
561                     if (r.IsAlive && r.Target == secondary)
562                     {
563                         throw new ArgumentException(SR.GetString(SR.TypeDescriptorAlreadyAssociated));
564                     }
565                 }
566             }
567
568             lock(associations)
569             {
570                 associations.Add(new WeakReference(secondary));
571             }
572         }
573
574         /// <devdoc>
575         ///     Creates an instance of the designer associated with the
576         ///     specified component.
577         /// </devdoc>
578         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2113:SecureLateBindingMethods")]
579         public static IDesigner CreateDesigner(IComponent component, Type designerBaseType) 
580         {
581             Type designerType = null;
582             IDesigner designer = null;
583
584             // Get the set of attributes for this type
585             //
586             AttributeCollection attributes = GetAttributes(component);
587             
588             for (int i = 0; i < attributes.Count; i++) 
589             {
590                 DesignerAttribute da = attributes[i] as DesignerAttribute;
591                 if (da != null) 
592                 {
593                     Type attributeBaseType = Type.GetType(da.DesignerBaseTypeName);
594                     if (attributeBaseType != null && attributeBaseType == designerBaseType) 
595                     {
596                         ISite site = component.Site;
597                         bool foundService = false;
598                         
599                         if (site != null) 
600                         {
601                             ITypeResolutionService tr = (ITypeResolutionService)site.GetService(typeof(ITypeResolutionService));
602                             if (tr != null) 
603                             {
604                                 foundService = true;
605                                 designerType = tr.GetType(da.DesignerTypeName);
606                             }
607                         }
608                         
609                         if (!foundService) 
610                         {
611                             designerType = Type.GetType(da.DesignerTypeName);
612                         }
613                         
614                         Debug.Assert(designerType != null, "It may be okay for the designer not to load, but we failed to load designer for component of type '" + component.GetType().FullName + "' because designer of type '" + da.DesignerTypeName + "'");
615                         if (designerType != null) 
616                         {
617                             break;
618                         }
619                     }
620                 }
621             }
622             
623             if (designerType != null) 
624             {
625                 designer = (IDesigner)SecurityUtils.SecureCreateInstance(designerType, null, true);
626             }
627
628             return designer;
629         }
630
631         /// <devdoc>
632         ///     This dynamically binds an EventDescriptor to a type.
633         /// </devdoc>
634         [ReflectionPermission(SecurityAction.LinkDemand, Flags=ReflectionPermissionFlag.MemberAccess)]
635         public static EventDescriptor CreateEvent(Type componentType, string name, Type type, params Attribute[] attributes) 
636         {
637             return new ReflectEventDescriptor(componentType, name, type, attributes);
638         }
639
640         /// <devdoc>
641         ///     This creates a new event descriptor identical to an existing event descriptor.  The new event descriptor
642         ///     has the specified metadata attributes merged with the existing metadata attributes.
643         /// </devdoc>
644         [ReflectionPermission(SecurityAction.LinkDemand, Flags=ReflectionPermissionFlag.MemberAccess)]
645         public static EventDescriptor CreateEvent(Type componentType, EventDescriptor oldEventDescriptor, params Attribute[] attributes) 
646         {
647             return new ReflectEventDescriptor(componentType, oldEventDescriptor, attributes);
648         }
649
650         /// <devdoc>
651         ///     This method will search internal tables within TypeDescriptor for 
652         ///     a TypeDescriptionProvider object that is associated with the given 
653         ///     data type.  If it finds one, it will delegate the call to that object.  
654         /// </devdoc>
655         public static object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)
656         {
657             if (objectType == null)
658             {
659                 throw new ArgumentNullException("objectType");
660             }
661
662             if (argTypes != null)
663             {
664                 if (args == null)
665                 {
666                     throw new ArgumentNullException("args");
667                 }
668
669                 if (argTypes.Length != args.Length)
670                 {
671                     throw new ArgumentException(SR.GetString(SR.TypeDescriptorArgsCountMismatch));
672                 }
673             }
674
675             object instance = null;
676
677             // See if the provider wants to offer a TypeDescriptionProvider to delegate to.  This allows
678             // a caller to have complete control over all object instantiation.
679             if (provider != null) {
680                 TypeDescriptionProvider p = provider.GetService(typeof(TypeDescriptionProvider)) as TypeDescriptionProvider;
681                 if (p != null) {
682                     instance = p.CreateInstance(provider, objectType, argTypes, args);
683                 }
684             }
685
686             if (instance == null) {
687                 instance = NodeFor(objectType).CreateInstance(provider, objectType, argTypes, args);
688             }
689
690             return instance;
691         }
692
693         /// <devdoc>
694         ///     This dynamically binds a PropertyDescriptor to a type.
695         /// </devdoc>
696         [ReflectionPermission(SecurityAction.LinkDemand, Flags=ReflectionPermissionFlag.MemberAccess)]
697         public static PropertyDescriptor CreateProperty(Type componentType, string name, Type type, params Attribute[] attributes) 
698         {
699             return new ReflectPropertyDescriptor(componentType, name, type, attributes);
700         }
701
702         /// <devdoc>
703         ///     This creates a new property descriptor identical to an existing property descriptor.  The new property descriptor
704         ///     has the specified metadata attributes merged with the existing metadata attributes.
705         /// </devdoc>
706         [ReflectionPermission(SecurityAction.LinkDemand, Flags=ReflectionPermissionFlag.MemberAccess)]
707         public static PropertyDescriptor CreateProperty(Type componentType, PropertyDescriptor oldPropertyDescriptor, params Attribute[] attributes) 
708         {
709
710             // We must do some special case work here for extended properties.  If the old property descriptor is really
711             // an extender property that is being surfaced on a component as a normal property, then we must
712             // do work here or else ReflectPropertyDescriptor will fail to resolve the get and set methods.  We check
713             // for the necessary ExtenderProvidedPropertyAttribute and if we find it, we create an
714             // ExtendedPropertyDescriptor instead.  We only do this if the component class is the same, since the user
715             // may want to re-route the property to a different target.
716             //
717             if (componentType == oldPropertyDescriptor.ComponentType) 
718             {
719                 ExtenderProvidedPropertyAttribute attr = (ExtenderProvidedPropertyAttribute)
720                                                          oldPropertyDescriptor.Attributes[
721                                                          typeof(ExtenderProvidedPropertyAttribute)];
722
723                 ReflectPropertyDescriptor reflectDesc = attr.ExtenderProperty as ReflectPropertyDescriptor;
724                 if (reflectDesc != null)
725                 {
726                     return new ExtendedPropertyDescriptor(oldPropertyDescriptor, attributes);
727                 }
728                 #if DEBUG
729                 else
730                 {
731                     DebugReflectPropertyDescriptor debugReflectDesc = attr.ExtenderProperty as DebugReflectPropertyDescriptor;
732                     if (debugReflectDesc != null)
733                     {
734                         return new DebugExtendedPropertyDescriptor(oldPropertyDescriptor, attributes);
735                     }
736                 }
737                 #endif
738             }
739
740             // This is either a normal prop or the caller has changed target classes.
741             //
742             return new ReflectPropertyDescriptor(componentType, oldPropertyDescriptor, attributes);
743         }
744
745         /// <devdoc>
746         ///     Debug code that runs the output of a TypeDescriptor query into a debug
747         ///     type descriptor that uses the V1.0 algorithm.  This code will assert
748         ///     if the two type descriptors do not agree.  This method returns true if
749         ///     validation should be performed for the type.
750         /// </devdoc>
751         #if DEBUG
752         private static bool DebugShouldValidate(object key)
753         {
754             // Check our switch first.
755             //
756             if (EnableValidation.Enabled)
757             {
758                 while(key != null)
759                 {
760                     // We only validate if there are no custom providers all the way
761                     // up the class chain.
762                     TypeDescriptionNode node = _providerTable[key] as TypeDescriptionNode;
763                     if (node != null && !(node.Provider is ReflectTypeDescriptionProvider))
764                     {
765                         return false;
766                     }
767     
768                     if (key is Type)
769                     {
770                         key = GetNodeForBaseType((Type)key);
771                     }
772                     else
773                     {
774                         key = key.GetType();
775                         if (((Type)key).IsCOMObject)
776                         {
777                             key = ComObjectType;
778                         }
779                     }
780                 }
781                 return true;
782             }
783             return false;
784         }
785         #endif
786
787         /// <devdoc>
788         ///     Debug code that runs the output of a TypeDescriptor query into a debug
789         ///     type descriptor that uses the V1.0 algorithm.  This code will assert
790         ///     if the two type descriptors do not agree.
791         /// </devdoc>
792         [Conditional("DEBUG")]
793         private static void DebugValidate(Type type, AttributeCollection attributes, AttributeCollection debugAttributes)
794         {
795             #if DEBUG
796             if (!DebugShouldValidate(type)) return;
797             DebugValidate(attributes, debugAttributes);
798             #endif
799         }
800
801         /// <devdoc>
802         ///     Debug code that runs the output of a TypeDescriptor query into a debug
803         ///     type descriptor that uses the V1.0 algorithm.  This code will assert
804         ///     if the two type descriptors do not agree.
805         /// </devdoc>
806         [Conditional("DEBUG")]
807         private static void DebugValidate(AttributeCollection attributes, AttributeCollection debugAttributes)
808         {
809             #if DEBUG
810
811             if (attributes.Count >= debugAttributes.Count)
812             {
813                 foreach(Attribute a in attributes)
814                 {
815                     if (!(a is GuidAttribute) && !(a is ComVisibleAttribute))
816                     {
817                         bool found = false;
818                         bool typeFound = false;
819     
820                         // Many attributes don't implement .Equals correctly,
821                         // so they will fail an equality check.  But we want to 
822                         // make sure that common ones like Browsable and ReadOnly
823                         // were correctly picked up.  So only check the ones in
824                         // component model.
825                         if (!a.GetType().FullName.StartsWith("System.Component"))
826                         {
827                             found = true;
828                             break;
829                         }
830     
831                         if (!found)
832                         {
833                             foreach(Attribute b in debugAttributes)
834                             {
835                                 if (!typeFound && a.GetType() == b.GetType())
836                                 {
837                                     typeFound = true;
838                                 }
839     
840                                 // Semitrust may throw here.  
841                                 try
842                                 {
843                                     if (a.Equals(b))
844                                     {
845                                         found = true;
846                                         break;
847                                     }
848                                 }
849                                 catch
850                                 {
851                                     found = true;
852                                     break;
853                                 }
854                             }
855                         }
856     
857                         if (!found && !a.IsDefaultAttribute())
858                         {
859                             if (typeFound)
860                             {
861                                 Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Attribute {0} was found but failed equality.  Perhaps attribute .Equals is not implemented correctly?", a.GetType().Name));
862                             }
863                             else
864                             {
865                                 Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Attribute {0} should not exist", a.GetType().Name));
866                             }
867                         }
868                     }
869                 }
870             }
871             else
872             {
873                 foreach(Attribute b in debugAttributes)
874                 {
875                     // We skip all interop attributes because interface merging has changed on purpose.  
876                     if (!(b is GuidAttribute) && !(b is ComVisibleAttribute) && !(b is InterfaceTypeAttribute) && !(b is ReadOnlyAttribute))
877                     {
878                         bool found = false;
879                         bool typeFound = false;
880     
881                         // Many attributes don't implement .Equals correctly,
882                         // so they will fail an equality check.  But we want to 
883                         // make sure that common ones like Browsable and ReadOnly
884                         // were correctly picked up.  So only check the ones in
885                         // component model.
886                         if (!b.GetType().FullName.StartsWith("System.Component"))
887                         {
888                             found = true;
889                             break;
890                         }
891     
892                         if (!found)
893                         {
894                             foreach(Attribute a in attributes)
895                             {
896                                 if (!typeFound && a.GetType() == b.GetType())
897                                 {
898                                     typeFound = true;
899                                 }
900     
901                                 // Semitrust may throw here.  
902                                 try
903                                 {
904                                     if (b.Equals(a))
905                                     {
906                                         found = true;
907                                         break;
908                                     }
909                                 }
910                                 catch
911                                 {
912                                     found = true;
913                                     break;
914                                 }
915                             }
916                         }
917     
918                         if (!found && !b.IsDefaultAttribute())
919                         {
920                             if (!typeFound)
921                             {
922                                 Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Attribute {0} should exist", b.GetType().Name));
923                             }
924                         }
925                     }
926                 }
927             }
928 #endif
929         }
930
931         /// <devdoc>
932         ///     Debug code that runs the output of a TypeDescriptor query into a debug
933         ///     type descriptor that uses the V1.0 algorithm.  This code will assert
934         ///     if the two type descriptors do not agree.
935         /// </devdoc>
936         [Conditional("DEBUG")]
937         private static void DebugValidate(AttributeCollection attributes, Type type)
938         {
939             #if DEBUG
940             if (!DebugShouldValidate(type)) return;
941             AttributeCollection debugAttributes = DebugTypeDescriptor.GetAttributes(type);
942             DebugValidate(attributes, debugAttributes);
943             #endif
944         }
945
946         /// <devdoc>
947         ///     Debug code that runs the output of a TypeDescriptor query into a debug
948         ///     type descriptor that uses the V1.0 algorithm.  This code will assert
949         ///     if the two type descriptors do not agree.
950         /// </devdoc>
951         [Conditional("DEBUG")]
952         private static void DebugValidate(AttributeCollection attributes, object instance, bool noCustomTypeDesc)
953         {
954             #if DEBUG
955             if (!DebugShouldValidate(instance)) return;
956             AttributeCollection debugAttributes = DebugTypeDescriptor.GetAttributes(instance, noCustomTypeDesc);
957             DebugValidate(attributes, debugAttributes);
958             #endif
959         }
960
961         /// <devdoc>
962         ///     Debug code that runs the output of a TypeDescriptor query into a debug
963         ///     type descriptor that uses the V1.0 algorithm.  This code will assert
964         ///     if the two type descriptors do not agree.
965         /// </devdoc>
966         [Conditional("DEBUG")]
967         private static void DebugValidate(TypeConverter converter, Type type)
968         {
969             #if DEBUG
970             if (!DebugShouldValidate(type)) return;
971             TypeConverter debugConverter = DebugTypeDescriptor.GetConverter(type);
972             Debug.Assert(debugConverter.GetType() == converter.GetType(), "TypeDescriptor engine Validation Failure.");
973             #endif
974         }
975
976         /// <devdoc>
977         ///     Debug code that runs the output of a TypeDescriptor query into a debug
978         ///     type descriptor that uses the V1.0 algorithm.  This code will assert
979         ///     if the two type descriptors do not agree.
980         /// </devdoc>
981         [Conditional("DEBUG")]
982         private static void DebugValidate(TypeConverter converter, object instance, bool noCustomTypeDesc)
983         {
984             #if DEBUG
985             if (!DebugShouldValidate(instance)) return;
986             TypeConverter debugConverter = DebugTypeDescriptor.GetConverter(instance, noCustomTypeDesc);
987             Debug.Assert(debugConverter.GetType() == converter.GetType(), "TypeDescriptor engine Validation Failure.");
988             #endif
989         }
990
991         /// <devdoc>
992         ///     Debug code that runs the output of a TypeDescriptor query into a debug
993         ///     type descriptor that uses the V1.0 algorithm.  This code will assert
994         ///     if the two type descriptors do not agree.
995         /// </devdoc>
996         [Conditional("DEBUG")]
997         private static void DebugValidate(EventDescriptorCollection events, Type type, Attribute[] attributes)
998         {
999             #if DEBUG
1000             if (!DebugShouldValidate(type)) return;
1001             EventDescriptorCollection debugEvents = DebugTypeDescriptor.GetEvents(type, attributes);
1002             Debug.Assert(debugEvents.Count == events.Count, "TypeDescriptor engine Validation Failure. Event counts differ.");
1003             foreach(EventDescriptor debugEvt in debugEvents)
1004             {
1005                 EventDescriptor evt = null;
1006                 
1007                 foreach(EventDescriptor realEvt in events)
1008                 {
1009                     if (realEvt.Name.Equals(debugEvt.Name) && realEvt.EventType == debugEvt.EventType && realEvt.ComponentType == debugEvt.ComponentType)
1010                     {
1011                         evt = realEvt;
1012                         break;
1013                     }
1014                 }
1015
1016                 Debug.Assert(evt != null, "TypeDescriptor engine Validation Failure. Event " + debugEvt.Name + " does not exist or is of the wrong type.");
1017                 if (evt != null)
1018                 {
1019                     AttributeCollection attrs = evt.Attributes;
1020                     if (attrs[typeof(AttributeProviderAttribute)] == null)
1021                     {
1022                         AttributeCollection debugAttrs = debugEvt.Attributes;
1023                         DebugValidate(evt.EventType, attrs, debugAttrs);
1024                     }
1025                 }
1026             }
1027             #endif
1028         }
1029
1030         /// <devdoc>
1031         ///     Debug code that runs the output of a TypeDescriptor query into a debug
1032         ///     type descriptor that uses the V1.0 algorithm.  This code will assert
1033         ///     if the two type descriptors do not agree.
1034         /// </devdoc>
1035         [Conditional("DEBUG")]
1036         private static void DebugValidate(EventDescriptorCollection events, object instance, Attribute[] attributes, bool noCustomTypeDesc)
1037         {
1038             #if DEBUG
1039             if (!DebugShouldValidate(instance)) return;
1040             EventDescriptorCollection debugEvents = DebugTypeDescriptor.GetEvents(instance, attributes, noCustomTypeDesc);
1041             Debug.Assert(debugEvents.Count == events.Count, "TypeDescriptor engine Validation Failure. Event counts differ.");
1042             foreach(EventDescriptor debugEvt in debugEvents)
1043             {
1044                 EventDescriptor evt = null;
1045                 
1046                 foreach(EventDescriptor realEvt in events)
1047                 {
1048                     if (realEvt.Name.Equals(debugEvt.Name) && realEvt.EventType == debugEvt.EventType && realEvt.ComponentType == debugEvt.ComponentType)
1049                     {
1050                         evt = realEvt;
1051                         break;
1052                     }
1053                 }
1054
1055                 Debug.Assert(evt != null, "TypeDescriptor engine Validation Failure. Event " + debugEvt.Name + " does not exist or is of the wrong type.");
1056                 if (evt != null)
1057                 {
1058                     AttributeCollection attrs = evt.Attributes;
1059                     if (attrs[typeof(AttributeProviderAttribute)] == null)
1060                     {
1061                         AttributeCollection debugAttrs = debugEvt.Attributes;
1062                         DebugValidate(evt.EventType, attrs, debugAttrs);
1063                     }
1064                 }
1065             }
1066             #endif
1067         }
1068
1069         /// <devdoc>
1070         ///     Debug code that runs the output of a TypeDescriptor query into a debug
1071         ///     type descriptor that uses the V1.0 algorithm.  This code will assert
1072         ///     if the two type descriptors do not agree.
1073         /// </devdoc>
1074         [Conditional("DEBUG")]
1075         private static void DebugValidate(PropertyDescriptorCollection properties, Type type, Attribute[] attributes)
1076         {
1077             #if DEBUG
1078             if (!DebugShouldValidate(type)) return;
1079             PropertyDescriptorCollection debugProperties = DebugTypeDescriptor.GetProperties(type, attributes);
1080
1081             if (debugProperties.Count > properties.Count)
1082             {
1083                 foreach(PropertyDescriptor debugProp in debugProperties)
1084                 {
1085                     PropertyDescriptor prop = null;
1086
1087                     foreach(PropertyDescriptor realProp in properties)
1088                     {
1089                         if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
1090                         {
1091                             prop = realProp;
1092                             break;
1093                         }
1094                     }
1095
1096                     if (prop == null)
1097                     {
1098                         Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should exist.", debugProp.Name, debugProp.GetType().Name));
1099                     }
1100                 }
1101             }
1102             else if (properties.Count > debugProperties.Count)
1103             {
1104                 foreach(PropertyDescriptor prop in properties)
1105                 {
1106                     PropertyDescriptor debugProp = null;
1107
1108                     foreach(PropertyDescriptor realProp in debugProperties)
1109                     {
1110                         if (realProp.Name.Equals(prop.Name) && realProp.PropertyType == prop.PropertyType && realProp.ComponentType == prop.ComponentType)
1111                         {
1112                             debugProp = realProp;
1113                             break;
1114                         }
1115                     }
1116
1117                     if (debugProp == null)
1118                     {
1119                         Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should not exist.", prop.Name, prop.GetType().Name));
1120                     }
1121                 }
1122             }
1123             else
1124             {
1125                 foreach(PropertyDescriptor debugProp in debugProperties)
1126                 {
1127                     PropertyDescriptor prop = null;
1128
1129                     foreach(PropertyDescriptor realProp in properties)
1130                     {
1131                         if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
1132                         {
1133                             prop = realProp;
1134                             break;
1135                         }
1136                     }
1137
1138                     Debug.Assert(prop != null, string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} exists but perhaps type mismatched?", debugProp.Name, debugProp.GetType().Name));
1139                     if (prop != null)
1140                     {
1141                         AttributeCollection attrs = prop.Attributes;
1142                         if (attrs[typeof(AttributeProviderAttribute)] == null)
1143                         {
1144                             AttributeCollection debugAttrs = debugProp.Attributes;
1145                             DebugValidate(prop.PropertyType, attrs, debugAttrs);
1146                         }
1147                     }
1148                 }
1149             }
1150 #endif
1151         }
1152
1153         /// <devdoc>
1154         ///     Debug code that runs the output of a TypeDescriptor query into a debug
1155         ///     type descriptor that uses the V1.0 algorithm.  This code will assert
1156         ///     if the two type descriptors do not agree.
1157         /// </devdoc>
1158         [Conditional("DEBUG")]
1159         private static void DebugValidate(PropertyDescriptorCollection properties, object instance, Attribute[] attributes, bool noCustomTypeDesc)
1160         {
1161             #if DEBUG
1162             if (!DebugShouldValidate(instance)) return;
1163             PropertyDescriptorCollection debugProperties = DebugTypeDescriptor.GetProperties(instance, attributes, noCustomTypeDesc);
1164
1165             if (debugProperties.Count > properties.Count)
1166             {
1167                 foreach(PropertyDescriptor debugProp in debugProperties)
1168                 {
1169                     PropertyDescriptor prop = null;
1170
1171                     foreach(PropertyDescriptor realProp in properties)
1172                     {
1173                         if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
1174                         {
1175                             prop = realProp;
1176                             break;
1177                         }
1178                     }
1179
1180                     if (prop == null)
1181                     {
1182                         Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should exist.", debugProp.Name, debugProp.GetType().Name));
1183                     }
1184                 }
1185             }
1186             else if (properties.Count > debugProperties.Count)
1187             {
1188                 foreach(PropertyDescriptor prop in properties)
1189                 {
1190                     PropertyDescriptor debugProp = null;
1191
1192                     foreach(PropertyDescriptor realProp in debugProperties)
1193                     {
1194                         if (realProp.Name.Equals(prop.Name) && realProp.PropertyType == prop.PropertyType && realProp.ComponentType == prop.ComponentType)
1195                         {
1196                             debugProp = realProp;
1197                             break;
1198                         }
1199                     }
1200
1201                     if (debugProp == null)
1202                     {
1203                         Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should not exist.", prop.Name, prop.GetType().Name));
1204                     }
1205                 }
1206             }
1207             else
1208             {
1209                 foreach(PropertyDescriptor debugProp in debugProperties)
1210                 {
1211                     PropertyDescriptor prop = null;
1212
1213                     foreach(PropertyDescriptor realProp in properties)
1214                     {
1215                         if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
1216                         {
1217                             prop = realProp;
1218                             break;
1219                         }
1220                     }
1221
1222                     Debug.Assert(prop != null, string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} exists but perhaps type mismatched?", debugProp.Name, debugProp.GetType().Name));
1223                     if (prop != null)
1224                     {
1225                         AttributeCollection attrs = prop.Attributes;
1226                         if (attrs[typeof(AttributeProviderAttribute)] == null)
1227                         {
1228                             AttributeCollection debugAttrs = debugProp.Attributes;
1229                             DebugValidate(prop.PropertyType, attrs, debugAttrs);
1230                         }
1231                     }
1232                 }
1233             }
1234 #endif
1235         }
1236
1237         /// <devdoc>
1238         ///     This  API is used to remove any members from the given
1239         ///     collection that do not match the attribute array.  If members
1240         ///     need to be removed, a new ArrayList wil be created that
1241         ///     contains only the remaining members. The API returns
1242         ///     NULL if it did not need to filter any members.
1243         /// </devdoc>
1244         private static ArrayList FilterMembers(IList members, Attribute[] attributes) {
1245             ArrayList newMembers = null;
1246             int memberCount = members.Count;
1247
1248             for (int idx = 0; idx < memberCount; idx++) {
1249
1250                 bool hide = false;
1251                 
1252                 for (int attrIdx = 0; attrIdx < attributes.Length; attrIdx++) {
1253                     if (ShouldHideMember((MemberDescriptor)members[idx], attributes[attrIdx])) {
1254                         hide = true;
1255                         break;
1256                     }
1257                 }
1258
1259                 if (hide) {
1260                     // We have to hide.  If this is the first time, we need to init
1261                     // newMembers to have all the valid members we have previously
1262                     // hit.
1263                     if (newMembers == null) {
1264                         newMembers = new ArrayList(memberCount);
1265                         for (int validIdx = 0; validIdx < idx; validIdx++) {
1266                             newMembers.Add(members[validIdx]);
1267                         }
1268                     }
1269                 }
1270                 else if (newMembers != null) {
1271                         newMembers.Add(members[idx]);
1272                 }
1273                 
1274             }
1275
1276             return newMembers;
1277         }
1278
1279         /// <devdoc>
1280         ///     The GetAssociation method returns the correct object to invoke 
1281         ///     for the requested type.  It never returns null.  
1282         /// </devdoc>
1283         [EditorBrowsable(EditorBrowsableState.Advanced)]
1284         public static object GetAssociation(Type type, object primary)
1285         {
1286             if (type == null)
1287             {
1288                 throw new ArgumentNullException("type");
1289             }
1290         
1291             if (primary == null)
1292             {
1293                 throw new ArgumentNullException("primary");
1294             }
1295
1296             object associatedObject = primary;
1297
1298             if (!type.IsInstanceOfType(primary))
1299             {
1300                 // Check our association table for a match.
1301                 //
1302                 Hashtable assocTable = _associationTable;
1303                 if (assocTable != null)
1304                 {
1305                     IList associations = (IList)assocTable[primary];
1306                     if (associations != null)
1307                     {
1308                         lock(associations)
1309                         {
1310                             for (int idx = associations.Count - 1; idx >= 0; idx--)
1311                             {
1312                                 // Look for an associated object that has a type that
1313                                 // matches the given type.
1314                                 //
1315                                 WeakReference weakRef = (WeakReference)associations[idx];
1316                                 object secondary = weakRef.Target;
1317                                 if (secondary == null)
1318                                 {
1319                                     Trace("Associations : Removing dead reference in assocation table");
1320                                     associations.RemoveAt(idx);
1321                                 }
1322                                 else if (type.IsInstanceOfType(secondary))
1323                                 {
1324                                     Trace("Associations : Associated {0} to {1}", primary.GetType().Name, secondary.GetType().Name);
1325                                     associatedObject = secondary;
1326                                 }
1327                             }
1328                         }
1329                     }
1330                 }
1331
1332                 // Not in our table.  We have a default association with a designer 
1333                 // if that designer is a component.
1334                 //
1335                 if (associatedObject == primary)
1336                 {
1337                     IComponent component = primary as IComponent;
1338                     if (component != null)
1339                     {
1340                         ISite site = component.Site;
1341
1342                         if (site != null && site.DesignMode)
1343                         {
1344                             IDesignerHost host = site.GetService(typeof(IDesignerHost)) as IDesignerHost;
1345                             if (host != null) 
1346                             {
1347                                 object designer = host.GetDesigner(component);
1348
1349                                 // We only use the designer if it has a compatible class.  If we
1350                                 // got here, we're probably hosed because the user just passed in
1351                                 // an object that this PropertyDescriptor can't munch on, but it's
1352                                 // clearer to use that object instance instead of it's designer.
1353                                 //
1354                                 if (designer != null && type.IsInstanceOfType(designer)) 
1355                                 {
1356                                     Trace("Associations : Associated {0} to {1}", primary.GetType().Name, designer.GetType().Name);
1357                                     associatedObject = designer;
1358                                 }
1359                             }
1360                         }
1361                     }
1362                 }
1363             }
1364
1365             return associatedObject;
1366         }
1367
1368         /// <devdoc>
1369         ///     Gets a collection of attributes for the specified type of component.
1370         /// </devdoc>
1371         public static AttributeCollection GetAttributes(Type componentType) 
1372         {
1373             if (componentType == null) 
1374             {
1375                 Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here");
1376                 return new AttributeCollection((Attribute[])null);
1377             }
1378
1379             AttributeCollection attributes = GetDescriptor(componentType, "componentType").GetAttributes();
1380             DebugValidate(attributes, componentType);
1381             return attributes;
1382         }
1383
1384         /// <devdoc>
1385         ///     Gets a collection of attributes for the specified component.
1386         /// </devdoc>
1387         public static AttributeCollection GetAttributes(object component) 
1388         {
1389             return GetAttributes(component, false);
1390         }
1391
1392         /// <devdoc>
1393         ///     Gets a collection of attributes for the specified component.
1394         /// </devdoc>
1395         [EditorBrowsable(EditorBrowsableState.Advanced)]
1396         public static AttributeCollection GetAttributes(object component, bool noCustomTypeDesc) 
1397         {
1398             if (component == null) 
1399             {
1400                 Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here");
1401                 return new AttributeCollection((Attribute[])null);
1402             }
1403
1404             // We create a sort of pipeline for mucking with metadata.  The pipeline
1405             // goes through the following process:
1406             //
1407             // 1.  Merge metadata from extenders.
1408             // 2.  Allow services to filter the metadata
1409             // 3.  If an attribute filter was specified, apply that.
1410             // 
1411             // The goal here is speed.  We get speed by not copying or
1412             // allocating memory.  We do this by allowing each phase of the
1413             // pipeline to cache its data in the object cache.  If
1414             // a phase makes a change to the results, this change must cause
1415             // successive phases to recompute their results as well.  "Results" is
1416             // always a collection, and the various stages of the pipeline may
1417             // replace or modify this collection (depending on if it's a
1418             // read-only IList or not).  It is possible for the orignal
1419             // descriptor or attribute collection to pass through the entire
1420             // pipeline without modification.
1421             // 
1422             ICustomTypeDescriptor typeDesc = GetDescriptor(component, noCustomTypeDesc);
1423             ICollection results = typeDesc.GetAttributes();
1424
1425             // If we are handed a custom type descriptor we have several choices of action
1426             // we can take.  If noCustomTypeDesc is true, it means that the custom type
1427             // descriptor is trying to find a baseline set of properties.  In this case
1428             // we should merge in extended properties, but we do not let designers filter
1429             // because we're not done with the property set yet.  If noCustomTypeDesc
1430             // is false, we don't do extender properties because the custom type descriptor
1431             // has already added them.  In this case, we are doing a final pass so we
1432             // want to apply filtering.  Finally, if the incoming object is not a custom
1433             // type descriptor, we do extenders and the filter.
1434             //
1435             if (component is ICustomTypeDescriptor)
1436             {
1437                 if (noCustomTypeDesc)
1438                 {
1439                     ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
1440                     if (extDesc != null)
1441                     {
1442                         ICollection extResults = extDesc.GetAttributes();
1443                         results = PipelineMerge(PIPELINE_ATTRIBUTES, results, extResults, component, null);
1444                     }
1445                 }
1446                 else
1447                 {
1448                     results = PipelineFilter(PIPELINE_ATTRIBUTES, results, component, null);
1449                 }
1450             }
1451             else
1452             {
1453                 IDictionary cache = GetCache(component);
1454
1455                 results = PipelineInitialize(PIPELINE_ATTRIBUTES, results, cache);
1456                 
1457                 ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
1458                 if (extDesc != null)
1459                 {
1460                     ICollection extResults = extDesc.GetAttributes();
1461                     results = PipelineMerge(PIPELINE_ATTRIBUTES, results, extResults, component, cache);
1462                 }
1463
1464                 results = PipelineFilter(PIPELINE_ATTRIBUTES, results, component, cache);
1465             }
1466
1467             AttributeCollection attrs = results as AttributeCollection;
1468             if (attrs == null)
1469             {
1470                 Trace("Attributes : Allocated new attribute collection for {0}", component.GetType().Name);
1471                 Attribute[] attrArray = new Attribute[results.Count];
1472                 results.CopyTo(attrArray, 0);
1473                 attrs = new AttributeCollection(attrArray);
1474             }
1475
1476             DebugValidate(attrs, component, noCustomTypeDesc);
1477             return attrs;
1478         }
1479
1480         /// <devdoc>
1481         ///     Helper function to obtain a cache for the given object.
1482         /// </devdoc>
1483         internal static IDictionary GetCache(object instance)
1484         {
1485             return NodeFor(instance).GetCache(instance);
1486         }
1487
1488         /// <devdoc>
1489         ///     Gets the name of the class for the specified component.
1490         /// </devdoc>
1491         public static string GetClassName(object component) 
1492         {
1493             return GetClassName(component, false);
1494         }
1495
1496         /// <devdoc>
1497         ///     Gets the name of the class for the specified component.
1498         /// </devdoc>
1499         [EditorBrowsable(EditorBrowsableState.Advanced)]
1500         public static string GetClassName(object component, bool noCustomTypeDesc) 
1501         {
1502             return GetDescriptor(component, noCustomTypeDesc).GetClassName();
1503         }
1504
1505         /// <devdoc>
1506         ///     Gets the name of the class for the specified type.
1507         /// </devdoc>
1508         public static string GetClassName(Type componentType) 
1509         {
1510             return GetDescriptor(componentType, "componentType").GetClassName();
1511         }
1512
1513         /// <devdoc>
1514         ///       The name of the class for the specified component.
1515         /// </devdoc>
1516         public static string GetComponentName(object component) 
1517         {
1518             return GetComponentName(component, false);
1519         }
1520
1521         /// <devdoc>
1522         ///    Gets the name of the class for the specified component.
1523         /// </devdoc>
1524         [EditorBrowsable(EditorBrowsableState.Advanced)]
1525         public static string GetComponentName(object component, bool noCustomTypeDesc) 
1526         {
1527             return GetDescriptor(component, noCustomTypeDesc).GetComponentName();
1528         }
1529
1530         /// <devdoc>
1531         ///    Gets a type converter for the type of the specified component.
1532         /// </devdoc>
1533         public static TypeConverter GetConverter(object component) 
1534         {
1535             return GetConverter(component, false);
1536         }
1537
1538         /// <devdoc>
1539         ///    Gets a type converter for the type of the specified component.
1540         /// </devdoc>
1541         [EditorBrowsable(EditorBrowsableState.Advanced)]
1542         public static TypeConverter GetConverter(object component, bool noCustomTypeDesc) 
1543         {
1544             TypeConverter converter = GetDescriptor(component, noCustomTypeDesc).GetConverter();
1545             DebugValidate(converter, component, noCustomTypeDesc);
1546             return converter;
1547         }
1548
1549         /// <devdoc>
1550         ///    Gets a type converter for the specified type.
1551         /// </devdoc>
1552         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
1553         public static TypeConverter GetConverter(Type type) 
1554         {
1555             TypeConverter converter = GetDescriptor(type, "type").GetConverter();
1556             DebugValidate(converter, type);
1557             return converter;
1558         }
1559
1560         /// <devdoc>
1561         ///     Gets the default event for the specified type of component.
1562         /// </devdoc>
1563         public static EventDescriptor GetDefaultEvent(Type componentType) 
1564         {
1565             if (componentType == null) 
1566             {
1567                 Debug.Fail("COMPAT:  Returning null, but you should not pass null here");
1568                 return null;
1569             }
1570
1571             return GetDescriptor(componentType, "componentType").GetDefaultEvent();
1572         }
1573
1574         /// <devdoc>
1575         ///     Gets the default event for the specified component.
1576         /// </devdoc>
1577         public static EventDescriptor GetDefaultEvent(object component) 
1578         {
1579             return GetDefaultEvent(component, false);
1580         }
1581
1582         /// <devdoc>
1583         ///     Gets the default event for a component.
1584         /// </devdoc>
1585         [EditorBrowsable(EditorBrowsableState.Advanced)]
1586         public static EventDescriptor GetDefaultEvent(object component, bool noCustomTypeDesc) 
1587         {
1588             if (component == null) 
1589             {
1590                 Debug.Fail("COMPAT:  Returning null, but you should not pass null here");
1591                 return null;
1592             }
1593
1594             return GetDescriptor(component, noCustomTypeDesc).GetDefaultEvent();
1595         }
1596
1597         /// <devdoc>
1598         ///     Gets the default property for the specified type of component.
1599         /// </devdoc>
1600         public static PropertyDescriptor GetDefaultProperty(Type componentType) 
1601         {
1602             if (componentType == null) 
1603             {
1604                 Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here");
1605                 return null;
1606             }
1607
1608             return GetDescriptor(componentType, "componentType").GetDefaultProperty();
1609         }
1610
1611         /// <devdoc>
1612         ///     Gets the default property for the specified component.
1613         /// </devdoc>
1614         public static PropertyDescriptor GetDefaultProperty(object component) 
1615         {
1616             return GetDefaultProperty(component, false);
1617         }
1618
1619         /// <devdoc>
1620         ///     Gets the default property for the specified component.
1621         /// </devdoc>
1622         [EditorBrowsable(EditorBrowsableState.Advanced)]
1623         public static PropertyDescriptor GetDefaultProperty(object component, bool noCustomTypeDesc) 
1624         {
1625             if (component == null) 
1626             {
1627                 Debug.Fail("COMPAT:  Returning null, but you should not pass null here");
1628                 return null;
1629             }
1630
1631             return GetDescriptor(component, noCustomTypeDesc).GetDefaultProperty();
1632         }
1633
1634         /// <devdoc>
1635         ///     Returns a custom type descriptor for the given type.
1636         ///     Performs arg checking so callers don't have to.
1637         /// </devdoc>
1638         internal static ICustomTypeDescriptor GetDescriptor(Type type, string typeName)
1639         {
1640             if (type == null)
1641             {
1642                 throw new ArgumentNullException(typeName);
1643             }
1644
1645             return NodeFor(type).GetTypeDescriptor(type);   
1646         }
1647
1648         /// <devdoc>
1649         ///     Returns a custom type descriptor for the given instance.
1650         ///     Performs arg checking so callers don't have to.  This
1651         ///     will call through to instance if it is a custom type
1652         ///     descriptor.
1653         /// </devdoc>
1654         internal static ICustomTypeDescriptor GetDescriptor(object component, bool noCustomTypeDesc)
1655         {
1656             if (component == null)
1657             {
1658                 throw new ArgumentException("component");
1659             }
1660
1661             if (component is IUnimplemented) {
1662                 throw new NotSupportedException(SR.GetString(SR.TypeDescriptorUnsupportedRemoteObject, component.GetType().FullName));
1663             }
1664
1665
1666             ICustomTypeDescriptor desc = NodeFor(component).GetTypeDescriptor(component);
1667             ICustomTypeDescriptor d = component as ICustomTypeDescriptor;
1668             if (!noCustomTypeDesc && d != null)
1669             {
1670                 desc = new MergedTypeDescriptor(d, desc);
1671             }
1672
1673             return desc;
1674         }
1675
1676         /// <devdoc>
1677         ///     Returns an extended custom type descriptor for the given instance.
1678         /// </devdoc>
1679         internal static ICustomTypeDescriptor GetExtendedDescriptor(object component)
1680         {
1681             if (component == null)
1682             {
1683                 throw new ArgumentException("component");
1684             }
1685
1686             return NodeFor(component).GetExtendedTypeDescriptor(component);
1687         }
1688
1689         /// <devdoc>
1690         ///     Gets an editor with the specified base type for the
1691         ///     specified component.
1692         /// </devdoc>
1693         public static object GetEditor(object component, Type editorBaseType) 
1694         {
1695             return GetEditor(component, editorBaseType, false);
1696         }
1697
1698         /// <devdoc>
1699         ///     Gets an editor with the specified base type for the
1700         ///     specified component.
1701         /// </devdoc>
1702         [EditorBrowsable(EditorBrowsableState.Advanced)]
1703         public static object GetEditor(object component, Type editorBaseType, bool noCustomTypeDesc) 
1704         {
1705             if (editorBaseType == null)
1706             {
1707                 throw new ArgumentNullException("editorBaseType");
1708             }
1709
1710             return GetDescriptor(component, noCustomTypeDesc).GetEditor(editorBaseType);
1711         }
1712
1713         /// <devdoc>
1714         ///    Gets an editor with the specified base type for the specified type.
1715         /// </devdoc>
1716         public static object GetEditor(Type type, Type editorBaseType) 
1717         {
1718             if (editorBaseType == null)
1719             {
1720                 throw new ArgumentNullException("editorBaseType");
1721             }
1722
1723             return GetDescriptor(type, "type").GetEditor(editorBaseType);
1724         }
1725
1726         /// <devdoc>
1727         ///     Gets a collection of events for a specified type of component.
1728         /// </devdoc>
1729         public static EventDescriptorCollection GetEvents(Type componentType) 
1730         {
1731             if (componentType == null) 
1732             {
1733                 Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here");
1734                 return new EventDescriptorCollection(null, true);
1735             }
1736
1737             return GetDescriptor(componentType, "componentType").GetEvents();
1738         }
1739
1740         /// <devdoc>
1741         ///     Gets a collection of events for a specified type of
1742         ///     component using a specified array of attributes as a filter.
1743         /// </devdoc>
1744         public static EventDescriptorCollection GetEvents(Type componentType, Attribute[] attributes) 
1745         {
1746             if (componentType == null) 
1747             {
1748                 Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here");
1749                 return new EventDescriptorCollection(null, true);
1750             }
1751
1752             EventDescriptorCollection events = GetDescriptor(componentType, "componentType").GetEvents(attributes);
1753
1754             if (attributes != null && attributes.Length > 0) {
1755                 ArrayList filteredEvents = FilterMembers(events, attributes);
1756                 if (filteredEvents != null) {
1757                     events = new EventDescriptorCollection((EventDescriptor[])filteredEvents.ToArray(typeof(EventDescriptor)), true);
1758                 }
1759             }
1760             
1761             DebugValidate(events, componentType, attributes);
1762             return events;
1763         }
1764
1765         /// <devdoc>
1766         ///     Gets a collection of events for a specified component.
1767         /// </devdoc>
1768         public static EventDescriptorCollection GetEvents(object component) 
1769         {
1770             return GetEvents(component, null, false);
1771         }
1772
1773         /// <devdoc>
1774         ///     Gets a collection of events for a specified component.
1775         /// </devdoc>
1776         [EditorBrowsable(EditorBrowsableState.Advanced)]
1777         public static EventDescriptorCollection GetEvents(object component, bool noCustomTypeDesc) 
1778         {
1779             return GetEvents(component, null, noCustomTypeDesc);
1780         }
1781
1782         /// <devdoc>
1783         ///     Gets a collection of events for a specified component 
1784         ///     using a specified array of attributes as a filter.
1785         /// </devdoc>
1786         public static EventDescriptorCollection GetEvents(object component, Attribute[] attributes) 
1787         {
1788             return GetEvents(component, attributes, false);
1789         }
1790
1791         /// <devdoc>
1792         ///     Gets a collection of events for a specified component 
1793         ///     using a specified array of attributes as a filter.
1794         /// </devdoc>
1795         [EditorBrowsable(EditorBrowsableState.Advanced)]
1796         public static EventDescriptorCollection GetEvents(object component, Attribute[] attributes, bool noCustomTypeDesc) 
1797         {
1798             if (component == null) 
1799             {
1800                 Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here");
1801                 return new EventDescriptorCollection(null, true);
1802             }
1803
1804             // We create a sort of pipeline for mucking with metadata.  The pipeline
1805             // goes through the following process:
1806             //
1807             // 1.  Merge metadata from extenders.
1808             // 2.  Allow services to filter the metadata
1809             // 3.  If an attribute filter was specified, apply that.
1810             // 
1811             // The goal here is speed.  We get speed by not copying or
1812             // allocating memory.  We do this by allowing each phase of the
1813             // pipeline to cache its data in the object cache.  If
1814             // a phase makes a change to the results, this change must cause
1815             // successive phases to recompute their results as well.  "Results" is
1816             // always a collection, and the various stages of the pipeline may
1817             // replace or modify this collection (depending on if it's a
1818             // read-only IList or not).  It is possible for the orignal
1819             // descriptor or attribute collection to pass through the entire
1820             // pipeline without modification.
1821             // 
1822             ICustomTypeDescriptor typeDesc = GetDescriptor(component, noCustomTypeDesc);
1823             ICollection results;
1824
1825             // If we are handed a custom type descriptor we have several choices of action
1826             // we can take.  If noCustomTypeDesc is true, it means that the custom type
1827             // descriptor is trying to find a baseline set of events.  In this case
1828             // we should merge in extended events, but we do not let designers filter
1829             // because we're not done with the event set yet.  If noCustomTypeDesc
1830             // is false, we don't do extender events because the custom type descriptor
1831             // has already added them.  In this case, we are doing a final pass so we
1832             // want to apply filtering.  Finally, if the incoming object is not a custom
1833             // type descriptor, we do extenders and the filter.
1834             //
1835             if (component is ICustomTypeDescriptor)
1836             {
1837                 results = typeDesc.GetEvents(attributes);
1838                 if (noCustomTypeDesc)
1839                 {
1840                     ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
1841                     if (extDesc != null)
1842                     {
1843                         ICollection extResults = extDesc.GetEvents(attributes);
1844                         results = PipelineMerge(PIPELINE_EVENTS, results, extResults, component, null);
1845                     }
1846                 }
1847                 else
1848                 {
1849                     results = PipelineFilter(PIPELINE_EVENTS, results, component, null);
1850                     results = PipelineAttributeFilter(PIPELINE_EVENTS, results, attributes, component, null);
1851                 }
1852             }
1853             else
1854             {
1855                 IDictionary cache = GetCache(component);
1856                 results = typeDesc.GetEvents(attributes);
1857                 results = PipelineInitialize(PIPELINE_EVENTS, results, cache);
1858                 ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
1859                 if (extDesc != null)
1860                 {
1861                     ICollection extResults = extDesc.GetEvents(attributes);
1862                     results = PipelineMerge(PIPELINE_EVENTS, results, extResults, component, cache);
1863                 }
1864
1865                 results = PipelineFilter(PIPELINE_EVENTS, results, component, cache);
1866                 results = PipelineAttributeFilter(PIPELINE_EVENTS, results, attributes, component, cache);
1867             }
1868
1869             EventDescriptorCollection evts = results as EventDescriptorCollection;
1870             if (evts == null)
1871             {
1872                 Trace("Events : Allocated new event collection for {0}", component.GetType().Name);
1873                 EventDescriptor[] eventArray = new EventDescriptor[results.Count];
1874                 results.CopyTo(eventArray, 0);
1875                 evts = new EventDescriptorCollection(eventArray, true);
1876             }
1877
1878             DebugValidate(evts, component, attributes, noCustomTypeDesc);
1879
1880             return evts;
1881         }
1882
1883         /// <devdoc>
1884         ///     This method is invoked during filtering when a name
1885         ///     collision is encountered between two properties or events.  This returns
1886         ///     a suffix that can be appended to the name to make
1887         ///     it unique.  This will first attempt ot use the name of the
1888         ///     extender.  Failing that it will fall back to a static
1889         ///     index that is continually incremented.
1890         /// </devdoc>
1891         private static string GetExtenderCollisionSuffix(MemberDescriptor member) 
1892         {
1893             string suffix = null;
1894
1895             ExtenderProvidedPropertyAttribute exAttr = member.Attributes[typeof(ExtenderProvidedPropertyAttribute)] as ExtenderProvidedPropertyAttribute;
1896             if (exAttr != null) 
1897             {
1898                 IExtenderProvider prov = exAttr.Provider;
1899
1900                 if (prov != null) 
1901                 {
1902                     string name = null;
1903                     IComponent component = prov as IComponent;
1904
1905                     if (component != null && component.Site != null) 
1906                     {
1907                         name = component.Site.Name;
1908                     }
1909
1910                     if (name == null || name.Length == 0) 
1911                     {
1912                         int ci = System.Threading.Interlocked.Increment(ref _collisionIndex) - 1;
1913                         name = ci.ToString(CultureInfo.InvariantCulture);
1914                     }
1915
1916                     suffix = string.Format(CultureInfo.InvariantCulture, "_{0}", name);
1917                 }
1918             }
1919
1920             return suffix;
1921         }
1922
1923         /// <devdoc>
1924         ///     The name of the specified component, or null if the component has no name.
1925         ///     In many cases this will return the same value as GetComponentName. If the
1926         ///     component resides in a nested container or has other nested semantics, it may
1927         ///     return a different fully qualfied name.
1928         /// </devdoc>
1929         public static string GetFullComponentName(object component) {
1930             if (component == null) throw new ArgumentNullException("component");
1931             return GetProvider(component).GetFullComponentName(component);
1932         }
1933
1934         private static Type GetNodeForBaseType(Type searchType)
1935         {
1936             if (searchType.IsInterface)
1937             {
1938                 return InterfaceType;
1939             }
1940             else if (searchType == InterfaceType)
1941             {
1942                 return null;
1943             }
1944             return searchType.BaseType;
1945         }
1946
1947         /// <devdoc>
1948         ///     Gets a collection of properties for a specified type of component.
1949         /// </devdoc>
1950         public static PropertyDescriptorCollection GetProperties(Type componentType) 
1951         {
1952             if (componentType == null) 
1953             {
1954                 Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here");
1955                 return new PropertyDescriptorCollection(null, true);
1956             }
1957
1958             return GetDescriptor(componentType, "componentType").GetProperties();
1959         }
1960
1961         /// <devdoc>
1962         ///    Gets a collection of properties for a specified type of 
1963         ///    component using a specified array of attributes as a filter.
1964         /// </devdoc>
1965         public static PropertyDescriptorCollection GetProperties(Type componentType, Attribute[] attributes) 
1966         {
1967             if (componentType == null) 
1968             {
1969                 Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here");
1970                 return new PropertyDescriptorCollection(null, true);
1971             }
1972
1973             PropertyDescriptorCollection properties = GetDescriptor(componentType, "componentType").GetProperties(attributes);
1974
1975             if (attributes != null && attributes.Length > 0) {
1976                 ArrayList filteredProperties = FilterMembers(properties, attributes);
1977                 if (filteredProperties != null) {
1978                     properties = new PropertyDescriptorCollection((PropertyDescriptor[])filteredProperties.ToArray(typeof(PropertyDescriptor)), true);
1979                 }
1980             }
1981             
1982             DebugValidate(properties, componentType, attributes);
1983             return properties;
1984         }
1985
1986         /// <devdoc>
1987         ///     Gets a collection of properties for a specified component.
1988         /// </devdoc>
1989         public static PropertyDescriptorCollection GetProperties(object component) 
1990         {
1991             return GetProperties(component, false);
1992         }
1993
1994         /// <devdoc>
1995         ///     Gets a collection of properties for a specified component.
1996         /// </devdoc>
1997         [EditorBrowsable(EditorBrowsableState.Advanced)]
1998         public static PropertyDescriptorCollection GetProperties(object component, bool noCustomTypeDesc) 
1999         {
2000             return GetPropertiesImpl(component, null, noCustomTypeDesc, true);
2001         }
2002
2003         /// <devdoc>
2004         ///    Gets a collection of properties for a specified 
2005         ///    component using a specified array of attributes
2006         ///    as a filter.
2007         /// </devdoc>
2008         public static PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes) 
2009         {
2010             return GetProperties(component, attributes, false);
2011         }
2012
2013         /// <devdoc>
2014         ///    <para>Gets a collection of properties for a specified 
2015         ///       component using a specified array of attributes
2016         ///       as a filter.</para>
2017         /// </devdoc>
2018         public static PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes, bool noCustomTypeDesc) {
2019             return GetPropertiesImpl(component, attributes, noCustomTypeDesc, false);
2020         }
2021
2022         /// <devdoc>
2023         ///    Gets a collection of properties for a specified component. Uses the attribute filter 
2024         ///    only if noAttributes is false. This is to preserve backward compat for the case when
2025         ///    no attribute filter was passed in (as against passing in null).
2026         /// </devdoc>
2027         private static PropertyDescriptorCollection GetPropertiesImpl(object component, Attribute[] attributes, bool noCustomTypeDesc, bool noAttributes) {
2028             if (component == null) 
2029             {
2030                 Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here");
2031                 return new PropertyDescriptorCollection(null, true);
2032             }
2033
2034             // We create a sort of pipeline for mucking with metadata.  The pipeline
2035             // goes through the following process:
2036             //
2037             // 1.  Merge metadata from extenders.
2038             // 2.  Allow services to filter the metadata
2039             // 3.  If an attribute filter was specified, apply that.
2040             // 
2041             // The goal here is speed.  We get speed by not copying or
2042             // allocating memory.  We do this by allowing each phase of the
2043             // pipeline to cache its data in the object cache.  If
2044             // a phase makes a change to the results, this change must cause
2045             // successive phases to recompute their results as well.  "Results" is
2046             // always a collection, and the various stages of the pipeline may
2047             // replace or modify this collection (depending on if it's a
2048             // read-only IList or not).  It is possible for the orignal
2049             // descriptor or attribute collection to pass through the entire
2050             // pipeline without modification.
2051             // 
2052             ICustomTypeDescriptor typeDesc = GetDescriptor(component, noCustomTypeDesc);
2053             ICollection results;
2054
2055             // If we are handed a custom type descriptor we have several choices of action
2056             // we can take.  If noCustomTypeDesc is true, it means that the custom type
2057             // descriptor is trying to find a baseline set of properties.  In this case
2058             // we should merge in extended properties, but we do not let designers filter
2059             // because we're not done with the property set yet.  If noCustomTypeDesc
2060             // is false, we don't do extender properties because the custom type descriptor
2061             // has already added them.  In this case, we are doing a final pass so we
2062             // want to apply filtering.  Finally, if the incoming object is not a custom
2063             // type descriptor, we do extenders and the filter.
2064             //
2065             if (component is ICustomTypeDescriptor)
2066             {
2067                 results = noAttributes ? typeDesc.GetProperties() : typeDesc.GetProperties(attributes);
2068                 if (noCustomTypeDesc)
2069                 {
2070                     ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
2071                     if (extDesc != null)
2072                     {
2073                         ICollection extResults = noAttributes ? extDesc.GetProperties() : extDesc.GetProperties(attributes);
2074                         results = PipelineMerge(PIPELINE_PROPERTIES, results, extResults, component, null);
2075                     }
2076                 }
2077                 else
2078                 {
2079                     results = PipelineFilter(PIPELINE_PROPERTIES, results, component, null);
2080                     results = PipelineAttributeFilter(PIPELINE_PROPERTIES, results, attributes, component, null);
2081                 }
2082             }
2083             else
2084             {
2085                 IDictionary cache = GetCache(component);
2086                 results = noAttributes ? typeDesc.GetProperties() : typeDesc.GetProperties(attributes);
2087                 results = PipelineInitialize(PIPELINE_PROPERTIES, results, cache);
2088                 ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
2089                 if (extDesc != null)
2090                 {
2091                     ICollection extResults = noAttributes ? extDesc.GetProperties() : extDesc.GetProperties(attributes);
2092                     results = PipelineMerge(PIPELINE_PROPERTIES, results, extResults, component, cache);
2093                 }
2094
2095                 results = PipelineFilter(PIPELINE_PROPERTIES, results, component, cache);
2096                 results = PipelineAttributeFilter(PIPELINE_PROPERTIES, results, attributes, component, cache);
2097             }
2098
2099             PropertyDescriptorCollection props = results as PropertyDescriptorCollection;
2100             if (props == null)
2101             {
2102                 Trace("Properties : Allocated new property collection for {0}", component.GetType().Name);
2103                 PropertyDescriptor[] propArray = new PropertyDescriptor[results.Count];
2104                 results.CopyTo(propArray, 0);
2105                 props = new PropertyDescriptorCollection(propArray, true);
2106             }
2107
2108             DebugValidate(props, component, attributes, noCustomTypeDesc);
2109
2110             return props;
2111         }
2112
2113         /// <devdoc>
2114         ///     The GetProvider method returns a type description provider for 
2115         ///     the given object or type.  This will always return a type description 
2116         ///     provider.  Even the default TypeDescriptor implementation is built on 
2117         ///     a TypeDescriptionProvider, and this will be returned unless there is 
2118         ///     another provider that someone else has added.
2119         /// </devdoc>
2120         [EditorBrowsable(EditorBrowsableState.Advanced)]
2121         public static TypeDescriptionProvider GetProvider(Type type)
2122         {
2123             if (type == null)
2124             {
2125                 throw new ArgumentNullException("type");
2126             }
2127
2128             return NodeFor(type, true);
2129         }
2130         
2131         /// <devdoc>
2132         ///     The GetProvider method returns a type description provider for 
2133         ///     the given object or type.  This will always return a type description 
2134         ///     provider.  Even the default TypeDescriptor implementation is built on 
2135         ///     a TypeDescriptionProvider, and this will be returned unless there is 
2136         ///     another provider that someone else has added.
2137         /// </devdoc>
2138         [EditorBrowsable(EditorBrowsableState.Advanced)]
2139         public static TypeDescriptionProvider GetProvider(object instance)
2140         {
2141             if (instance == null)
2142             {
2143                 throw new ArgumentNullException("instance");
2144             }
2145
2146             return NodeFor(instance, true);
2147         }
2148
2149         /// <devdoc>
2150         ///     This method returns a type description provider, but instead of creating
2151         ///     a delegating provider for the type, this will walk all base types until
2152         ///     it locates a provider.  The provider returned cannot be cached.  This
2153         ///     method is used by the DelegatingTypeDescriptionProvider to efficiently
2154         ///     locate the provider to delegate to.
2155         /// </devdoc>
2156         internal static TypeDescriptionProvider GetProviderRecursive(Type type) {
2157             return NodeFor(type, false);    
2158         }
2159
2160         /// <devdoc>
2161         ///     Returns an Type instance that can be used to perform reflection.
2162         /// </devdoc>
2163         [EditorBrowsable(EditorBrowsableState.Advanced)]
2164         public static Type GetReflectionType(Type type)
2165         {
2166             if (type == null)
2167             {
2168                 throw new ArgumentNullException("type");
2169             }
2170
2171             return NodeFor(type).GetReflectionType(type);
2172         }
2173
2174         /// <devdoc>
2175         ///     Returns an Type instance that can be used to perform reflection.
2176         /// </devdoc>
2177         [EditorBrowsable(EditorBrowsableState.Advanced)]
2178         public static Type GetReflectionType(object instance)
2179         {
2180             if (instance == null)
2181             {
2182                 throw new ArgumentNullException("instance");
2183             }
2184
2185             return NodeFor(instance).GetReflectionType(instance);
2186         }
2187
2188         /// <devdoc>
2189         ///     Retrieves the head type description node for a type.
2190         ///     A head node pointing to a reflection based type description
2191         ///     provider will be created on demand.  This does not create
2192         ///     a delegator, in which case the node returned may be
2193         ///     a base type node.
2194         /// </devdoc>
2195         private static TypeDescriptionNode NodeFor(Type type) {
2196             return NodeFor(type, false);
2197         }
2198
2199         /// <devdoc>
2200         ///     Retrieves the head type description node for a type.
2201         ///     A head node pointing to a reflection based type description
2202         ///     provider will be created on demand.
2203         ///
2204         ///     If createDelegator is true, this method will create a delegation
2205         ///     node for a type if the type has no node of its own.  Delegation
2206         ///     nodes should be created if you are going to hand this node
2207         ///     out to a user.  Without a delegation node, user code could
2208         ///     skip providers that are added after their call.  Delegation
2209         ///     nodes solve that problem.
2210         ///
2211         ///     If createDelegator is false, this method will recurse up the
2212         ///     base type chain looking for nodes.  
2213         /// </devdoc>
2214         private static TypeDescriptionNode NodeFor(Type type, bool createDelegator) {
2215             Debug.Assert(type != null, "Caller should validate");
2216             CheckDefaultProvider(type);
2217
2218             // First, check our provider type table to see if we have a matching
2219             // provider for this type.  The provider type table is a cache that
2220             // matches types to providers.  When a new provider is added or
2221             // an existing one removed, the provider type table is torn
2222             // down and automatically rebuilt on demand.
2223             //
2224             TypeDescriptionNode node = null;
2225             Type searchType = type;
2226             
2227             while (node == null) {
2228                     node = (TypeDescriptionNode)_providerTypeTable[searchType];
2229                     if (node == null) {
2230                         node = (TypeDescriptionNode)_providerTable[searchType];
2231                     }
2232             
2233                     if (node == null) {
2234                         Type baseType = GetNodeForBaseType(searchType);
2235                     
2236                         if (searchType == typeof(object) || baseType == null) {
2237                         
2238                             lock (_providerTable) {
2239                                 node = (TypeDescriptionNode)_providerTable[searchType];
2240                                 
2241                                 if (node == null) {
2242                                     // The reflect type description provider is a default provider that
2243                                     // can provide type information for all objects.
2244                                     node = new TypeDescriptionNode(new ReflectTypeDescriptionProvider());
2245                                     _providerTable[searchType] = node;
2246                                     Trace("Nodes : Allocated new type node.  Now {0} nodes", _providerTable.Count);
2247                                 }     
2248                             }
2249                             
2250                         }
2251                         else if (createDelegator) {
2252                             node = new TypeDescriptionNode(new DelegatingTypeDescriptionProvider(baseType));
2253                             lock (_providerTable) {
2254                                 _providerTypeTable[searchType] = node;
2255                             }
2256                         }
2257                         else {
2258                             // Continue our search
2259                             searchType = baseType;
2260                         }    
2261                     }
2262                 }
2263
2264             return node;
2265         }
2266
2267         /// <devdoc>
2268         ///     Retrieves the head type description node for an instance.
2269         ///     Instance-based node lists are rare.  If a node list is not
2270         ///     available for a given instance, this will return the head node
2271         ///     for the instance's type.
2272         /// </devdoc>
2273         private static TypeDescriptionNode NodeFor(object instance)
2274         {
2275             return NodeFor(instance, false);
2276         }
2277
2278         /// <devdoc>
2279         ///     Retrieves the head type description node for an instance.
2280         ///     Instance-based node lists are rare.  If a node list is not
2281         ///     available for a given instance, this will return the head node
2282         ///     for the instance's type.  This variation offers a bool called
2283         ///     createDelegator.  If true and there is no node list for this
2284         ///     instance, NodeFor will create a temporary "delegator node" that,
2285         ///     when queried, will delegate to the type stored in the instance.
2286         ///     This is done on demand, which means if someone else added a
2287         ///     type description provider for the instance's type the delegator
2288         ///     would pick up the new type.  If a query is being made that does
2289         ///     not involve publicly exposing the type description provider for
2290         ///     the instance, the query should pass in fase (the default) for
2291         ///     createDelegator because no object will be created.
2292         /// </devdoc>
2293         private static TypeDescriptionNode NodeFor(object instance, bool createDelegator)
2294         {
2295             // For object instances, the provider cache key is not the object (that
2296             // would keep it in memory).  Instead, it is a subclass of WeakReference
2297             // that overrides GetHashCode and Equals to make it appear to be the
2298             // object it is wrapping.  A GC'd object causes WeakReference to return
2299             // false for all .Equals, but it always returns a valid hash code.
2300
2301             Debug.Assert(instance != null, "Caller should validate");
2302
2303             TypeDescriptionNode node = (TypeDescriptionNode)_providerTable[instance];
2304             if (node == null)
2305             {
2306                 Type type = instance.GetType();
2307
2308                 if (type.IsCOMObject)
2309                 {
2310                     type = ComObjectType;
2311                 }
2312
2313                 if (createDelegator)
2314                 {
2315                     node = new TypeDescriptionNode(new DelegatingTypeDescriptionProvider(type));
2316                     Trace("Nodes : Allocated new instance node for {0}.  Now {1} nodes", type.Name, _providerTable.Count);
2317                 }
2318                 else
2319                 {
2320                     node = NodeFor(type);
2321                 }
2322             }
2323
2324             return node;
2325         }
2326
2327         /// <devdoc>
2328         ///     Simple linked list code to remove an element
2329         ///     from the list.  Returns the new head to the
2330         ///     list.  If the head points to an instance of
2331         ///     DelegatingTypeDescriptionProvider, we clear the
2332         ///     node because all it is doing is delegating elsewhere.
2333         ///
2334         ///     Note that this behaves a little differently from normal
2335         ///     linked list code.  In a normal linked list, you remove 
2336         ///     then target node and fixup the links.  In this linked
2337         ///     list, we remove the node AFTER the target node, fixup
2338         ///     the links, and fixup the underlying providers that each
2339         ///     node references.  The reason for this is that most
2340         ///     providers keep a reference to the previous provider,
2341         ///     which is exposed as one of these nodes.  Therefore,
2342         ///     to remove a provider the node following is most likely
2343         ///     referenced by that provider
2344         /// </devdoc>
2345         private static void NodeRemove(object key, TypeDescriptionProvider provider)
2346         {
2347             lock(_providerTable)
2348             {
2349                 TypeDescriptionNode head = (TypeDescriptionNode)_providerTable[key];
2350                 TypeDescriptionNode target = head;
2351 //                TypeDescriptionNode prev = null;
2352
2353                 while(target != null && target.Provider != provider)
2354                 {
2355 //                    prev = target;
2356                     target = target.Next;
2357                 }
2358
2359                 if (target != null)
2360                 {
2361                     // We have our target node.  There are three cases
2362                     // to consider:  the target is in the middle, the head,
2363                     // or the end.
2364
2365                     if (target.Next != null) {
2366                         // If there is a node after the target node,
2367                         // steal the node's provider and store it
2368                         // at the target location.  This removes
2369                         // the provider at the target location without
2370                         // the need to modify providers which may be
2371                         // pointing to "target".  
2372                         target.Provider = target.Next.Provider;
2373
2374                         // Now remove target.Next from the list
2375                         target.Next = target.Next.Next;
2376
2377                         // If the new provider we got is a delegating
2378                         // provider, we can remove this node from 
2379                         // the list.  The delegating provider should
2380                         // always be at the end of the node list.
2381                         if (target == head && target.Provider is DelegatingTypeDescriptionProvider) {
2382                             Debug.Assert(target.Next == null, "Delegating provider should always be the last provider in the chain.");
2383                             _providerTable.Remove(key);
2384                         }
2385                     }
2386                     else if (target != head) {
2387                         // If target is the last node, we can't
2388                         // assign a new provider over to it.  What
2389                         // we can do, however, is assign a delegating
2390                         // provider into the target node.  This routes
2391                         // requests from the previous provider into
2392                         // the next base type provider list.
2393
2394                         // We don't do this if the target is the head.
2395                         // In that case, we can remove the node
2396                         // altogether since no one is pointing to it.
2397                         
2398                         Type keyType = key as Type;
2399                         if (keyType == null) keyType = key.GetType();
2400                         
2401                         target.Provider = new DelegatingTypeDescriptionProvider(keyType.BaseType);
2402                     }
2403                     else {
2404                         _providerTable.Remove(key);
2405                     }
2406
2407                     // Finally, clear our cache of provider types; it might be invalid 
2408                     // now.
2409                     _providerTypeTable.Clear();
2410                 }
2411             }
2412         }
2413
2414         /// <devdoc>
2415         ///     This is the last stage in our filtering pipeline.  Here, we apply any
2416         ///     user-defined filter.  
2417         /// </devdoc>
2418         private static ICollection PipelineAttributeFilter(int pipelineType, ICollection members, Attribute[] filter, object instance, IDictionary cache)
2419         {
2420             Debug.Assert(pipelineType != PIPELINE_ATTRIBUTES, "PipelineAttributeFilter is not supported for attributes");
2421             
2422             IList list = members as ArrayList;
2423
2424             if (filter == null || filter.Length == 0)
2425             {
2426                 return members;
2427             }
2428
2429             // Now, check our cache.  The cache state is only valid
2430             // if the data coming into us is read-only.  If it is read-write,
2431             // that means something higher in the pipeline has already changed
2432             // it so we must recompute anyway.
2433             //
2434             if (cache != null && (list == null || list.IsReadOnly))
2435             {
2436                 AttributeFilterCacheItem filterCache = cache[_pipelineAttributeFilterKeys[pipelineType]] as AttributeFilterCacheItem;
2437                 if (filterCache != null && filterCache.IsValid(filter))
2438                 {
2439                     return filterCache.FilteredMembers;
2440                 }
2441             }
2442
2443             // Our cache did not contain the correct state, so generate it.
2444             //
2445             if (list == null || list.IsReadOnly)
2446             {
2447                 Trace("Pipeline : Filter needs to create member list for {0}", instance.GetType().Name);
2448                 list = new ArrayList(members);
2449             }
2450
2451             ArrayList filterResult = FilterMembers(list, filter);
2452             if (filterResult != null) list = filterResult;
2453
2454             // And, if we have a cache, store the updated state into it for future reference.
2455             //
2456             if (cache != null)
2457             {
2458                 ICollection cacheValue;
2459
2460                 switch(pipelineType)
2461                 {
2462                     case PIPELINE_PROPERTIES:
2463                         PropertyDescriptor[] propArray = new PropertyDescriptor[list.Count];
2464                         list.CopyTo(propArray, 0);
2465                         cacheValue = new PropertyDescriptorCollection(propArray, true);
2466                         break;
2467
2468                     case PIPELINE_EVENTS:
2469                         EventDescriptor[] eventArray = new EventDescriptor[list.Count];
2470                         list.CopyTo(eventArray, 0);
2471                         cacheValue = new EventDescriptorCollection(eventArray, true);
2472                         break;
2473
2474                     default:
2475                         Debug.Fail("unknown pipeline type");
2476                         cacheValue = null;
2477                         break;
2478                 }
2479
2480                 Trace("Pipeline : Attribute Filter results being cached for {0}", instance.GetType().Name);
2481                 AttributeFilterCacheItem filterCache = new AttributeFilterCacheItem(filter, cacheValue);
2482                 cache[_pipelineAttributeFilterKeys[pipelineType]] = filterCache;
2483             }
2484
2485             return list;
2486         }
2487
2488         /// <devdoc>
2489         ///     Metdata filtering is the third stage of our pipeline.  
2490         ///     In this stage we check to see if the given object is a
2491         ///     sited component that provides the ITypeDescriptorFilterService
2492         ///     object.  If it does, we allow the TDS to filter the metadata.
2493         ///     This will use the cache, if available, to store filtered
2494         ///     metdata.
2495         /// </devdoc>
2496         private static ICollection PipelineFilter(int pipelineType, ICollection members, object instance, IDictionary cache)
2497         {
2498             IComponent component = instance as IComponent;
2499             ITypeDescriptorFilterService componentFilter = null;
2500
2501             if (component != null)
2502             {
2503                 ISite site = component.Site;
2504                 if (site != null)
2505                 {
2506                     componentFilter = site.GetService(typeof(ITypeDescriptorFilterService)) as ITypeDescriptorFilterService;
2507                 }
2508             }
2509
2510             // If we have no filter, there is nothing for us to do.
2511             //
2512             IList list = members as ArrayList;
2513
2514             if (componentFilter == null)
2515             {
2516                 Debug.Assert(cache == null || list == null || !cache.Contains(_pipelineFilterKeys[pipelineType]), "Earlier pipeline stage should have removed our cache");
2517                 return members;
2518             }
2519
2520             // Now, check our cache.  The cache state is only valid
2521             // if the data coming into us is read-only.  If it is read-write,
2522             // that means something higher in the pipeline has already changed
2523             // it so we must recompute anyway.
2524             //
2525             if (cache != null && (list == null || list.IsReadOnly))
2526             {
2527                 FilterCacheItem cacheItem = cache[_pipelineFilterKeys[pipelineType]] as FilterCacheItem;
2528                 if (cacheItem != null && cacheItem.IsValid(componentFilter)) {
2529                     return cacheItem.FilteredMembers;
2530                 }
2531             }
2532
2533             // Cache either is dirty or doesn't exist.  Re-filter the members.
2534             // We need to build an IDictionary of key->value pairs and invoke
2535             // Filter* on the filter service.
2536             //
2537             OrderedDictionary filterTable = new OrderedDictionary(members.Count);
2538             bool cacheResults;
2539
2540             switch(pipelineType)
2541             {
2542                 case PIPELINE_ATTRIBUTES:
2543                     foreach(Attribute attr in members)
2544                     {
2545                         filterTable[attr.TypeId] = attr;
2546                     }
2547                     cacheResults = componentFilter.FilterAttributes(component, filterTable);
2548                     break;
2549
2550                 case PIPELINE_PROPERTIES:
2551                 case PIPELINE_EVENTS:
2552                     foreach(MemberDescriptor desc in members)
2553                     {
2554                         string descName = desc.Name;
2555                         // We must handle the case of duplicate property names
2556                         // because extender providers can provide any arbitrary
2557                         // name.  Our rule for this is simple:  If we find a
2558                         // duplicate name, resolve it back to the extender
2559                         // provider that offered it and append "_" + the
2560                         // provider name.  If the provider has no name,
2561                         // then append the object hash code.
2562                         //
2563                         if (filterTable.Contains(descName)) 
2564                         {
2565                             // First, handle the new property.  Because
2566                             // of the order in which we added extended
2567                             // properties earlier in the pipeline, we can be 
2568                             // sure that the new property is an extender.  We
2569                             // cannot be sure that the existing property
2570                             // in the table is an extender, so we will 
2571                             // have to check.
2572                             //
2573                             string suffix = GetExtenderCollisionSuffix(desc);
2574                             Debug.Assert(suffix != null, "Name collision with non-extender property.");
2575                             if (suffix != null) 
2576                             {
2577                                 filterTable[descName + suffix] = desc;
2578                             }
2579
2580                             // Now, handle the original property.
2581                             //
2582                             MemberDescriptor origDesc = (MemberDescriptor)filterTable[descName];
2583                             suffix = GetExtenderCollisionSuffix(origDesc);
2584                             if (suffix != null) 
2585                             {
2586                                 filterTable.Remove(descName);
2587                                 filterTable[origDesc.Name + suffix] = origDesc;
2588                             }
2589                         }
2590                         else 
2591                         {
2592                             filterTable[descName] = desc;
2593                         }
2594                     }
2595                     if (pipelineType == PIPELINE_PROPERTIES)
2596                     {
2597                         cacheResults = componentFilter.FilterProperties(component, filterTable);
2598                     }
2599                     else
2600                     {
2601                         cacheResults = componentFilter.FilterEvents(component, filterTable);
2602                     }
2603                     break;
2604
2605                 default:
2606                     Debug.Fail("unknown pipeline type");
2607                     cacheResults = false;
2608                     break;
2609             }
2610
2611             // See if we can re-use the IList were were passed.  If we can,
2612             // it is more efficient to re-use its slots than to generate new ones.
2613             //
2614             if (list == null || list.IsReadOnly)
2615             {
2616                 Trace("Pipeline : Filter needs to create member list for {0}", instance.GetType().Name);
2617                 list = new ArrayList(filterTable.Values);
2618             }
2619             else
2620             {
2621                 list.Clear();
2622                 foreach(object obj in filterTable.Values)
2623                 {
2624                     list.Add(obj);
2625                 }
2626             }
2627
2628             // Component filter has requested that we cache these
2629             // new changes.  We store them as a correctly typed collection
2630             // so on successive invocations we can simply return.  Note that
2631             // we always return the IList so that successive stages in the
2632             // pipeline can modify it.
2633             //
2634             if (cacheResults && cache != null)
2635             {
2636                 ICollection cacheValue;
2637
2638                 switch(pipelineType)
2639                 {
2640                     case PIPELINE_ATTRIBUTES:
2641                         Attribute[] attrArray = new Attribute[list.Count];
2642                         try
2643                         {
2644                             list.CopyTo(attrArray, 0);
2645                         }
2646                         catch(InvalidCastException)
2647                         {
2648                             throw new ArgumentException(SR.GetString(SR.TypeDescriptorExpectedElementType, typeof(Attribute).FullName));
2649                         }
2650                         cacheValue = new AttributeCollection(attrArray);
2651                         break;
2652
2653                     case PIPELINE_PROPERTIES:
2654                         PropertyDescriptor[] propArray = new PropertyDescriptor[list.Count];
2655                         try
2656                         {
2657                             list.CopyTo(propArray, 0);
2658                         }
2659                         catch(InvalidCastException)
2660                         {
2661                             throw new ArgumentException(SR.GetString(SR.TypeDescriptorExpectedElementType, typeof(PropertyDescriptor).FullName));
2662                         }
2663                         cacheValue = new PropertyDescriptorCollection(propArray, true);
2664                         break;
2665
2666                     case PIPELINE_EVENTS:
2667                         EventDescriptor[] eventArray = new EventDescriptor[list.Count];
2668                         try
2669                         {
2670                             list.CopyTo(eventArray, 0);
2671                         }
2672                         catch(InvalidCastException)
2673                         {
2674                             throw new ArgumentException(SR.GetString(SR.TypeDescriptorExpectedElementType, typeof(EventDescriptor).FullName));
2675                         }
2676                         cacheValue = new EventDescriptorCollection(eventArray, true);
2677                         break;
2678
2679                     default:
2680                         Debug.Fail("unknown pipeline type");
2681                         cacheValue = null;
2682                         break;
2683                 }
2684
2685                 Trace("Pipeline : Filter results being cached for {0}", instance.GetType().Name);
2686
2687                 FilterCacheItem cacheItem = new FilterCacheItem(componentFilter, cacheValue);
2688                 cache[_pipelineFilterKeys[pipelineType]] = cacheItem;
2689                 cache.Remove(_pipelineAttributeFilterKeys[pipelineType]);
2690             }
2691
2692             return list;
2693         }
2694
2695         /// <devdoc>
2696         /// This is the first stage in the pipeline.  This checks the incoming member collection and if it
2697         /// differs from what we have seen in the past, it invalidates all successive pipelines.
2698         /// </devdoc>
2699         private static ICollection PipelineInitialize (int pipelineType, ICollection members, IDictionary cache) {
2700             if (cache != null) {
2701
2702                 bool cacheValid = true;
2703                 
2704                 ICollection cachedMembers = cache[_pipelineInitializeKeys[pipelineType]] as ICollection;
2705                 if (cachedMembers != null && cachedMembers.Count == members.Count) {
2706                     IEnumerator cacheEnum = cachedMembers.GetEnumerator();
2707                     IEnumerator memberEnum = members.GetEnumerator();
2708
2709                     while(cacheEnum.MoveNext() && memberEnum.MoveNext()) {
2710                         if (cacheEnum.Current != memberEnum.Current) {
2711                             cacheValid = false;
2712                             break;
2713                         }    
2714                     }
2715                 }
2716
2717                 if (!cacheValid) {
2718                     // The cache wasn't valid.  Remove all subsequent cache layers
2719                     // and then save off new data.
2720                     cache.Remove(_pipelineMergeKeys[pipelineType]);
2721                     cache.Remove(_pipelineFilterKeys[pipelineType]);
2722                     cache.Remove(_pipelineAttributeFilterKeys[pipelineType]);
2723                     cache[_pipelineInitializeKeys[pipelineType]] = members;
2724                 }
2725             }
2726             
2727             return members;
2728         }
2729
2730         /// <devdoc>
2731         ///     Metadata merging is the second stage of our metadata pipeline.  This stage
2732         ///     merges extended metdata with primary metadata, and stores it in 
2733         ///     the cache if it is available.
2734         /// </devdoc>
2735         private static ICollection PipelineMerge(int pipelineType, ICollection primary, ICollection secondary, object instance, IDictionary cache)
2736         {
2737             // If there is no secondary collection, there is nothing to merge.
2738             //
2739             if (secondary == null || secondary.Count == 0)
2740             {
2741                 return primary;
2742             }
2743
2744             // Next, if we were given a cache, see if it has accurate data.
2745             //
2746             if (cache != null)
2747             {
2748                 ICollection mergeCache = cache[_pipelineMergeKeys[pipelineType]] as ICollection;
2749                 if (mergeCache != null && mergeCache.Count == (primary.Count + secondary.Count))
2750                 {
2751                     // Walk the merge cache.
2752                     IEnumerator mergeEnum = mergeCache.GetEnumerator();
2753                     IEnumerator primaryEnum = primary.GetEnumerator();
2754                     bool match = true;
2755
2756                     while(primaryEnum.MoveNext() && mergeEnum.MoveNext())
2757                     {
2758                         if (primaryEnum.Current != mergeEnum.Current)
2759                         {
2760                             match = false;
2761                             break;
2762                         }
2763                     }
2764
2765                     if (match)
2766                     {
2767                         IEnumerator secondaryEnum = secondary.GetEnumerator();
2768
2769                         while(secondaryEnum.MoveNext() && mergeEnum.MoveNext())
2770                         {
2771                             if (secondaryEnum.Current != mergeEnum.Current)
2772                             {
2773                                 match = false;
2774                                 break;
2775                             }
2776                         }
2777                     }
2778
2779                     if (match)
2780                     {
2781                         return mergeCache;
2782                     }
2783                 }
2784             }
2785
2786             // Our cache didn't match.  We need to merge metadata and return
2787             // the merged copy.  We create an array list here, rather than
2788             // an array, because we want successive sections of the 
2789             // pipeline to be able to modify it.
2790             //
2791             ArrayList list = new ArrayList(primary.Count + secondary.Count);
2792             foreach(object obj in primary)
2793             {
2794                 list.Add(obj);
2795             }
2796             foreach(object obj in secondary)
2797             {
2798                 list.Add(obj);
2799             }
2800
2801             if (cache != null)
2802             {
2803                 ICollection cacheValue;
2804
2805                 switch(pipelineType)
2806                 {
2807                     case PIPELINE_ATTRIBUTES:
2808                         Attribute[] attrArray = new Attribute[list.Count];
2809                         list.CopyTo(attrArray, 0);
2810                         cacheValue = new AttributeCollection(attrArray);
2811                         break;
2812
2813                     case PIPELINE_PROPERTIES:
2814                         PropertyDescriptor[] propArray = new PropertyDescriptor[list.Count];
2815                         list.CopyTo(propArray, 0);
2816                         cacheValue = new PropertyDescriptorCollection(propArray, true);
2817                         break;
2818
2819                     case PIPELINE_EVENTS:
2820                         EventDescriptor[] eventArray = new EventDescriptor[list.Count];
2821                         list.CopyTo(eventArray, 0);
2822                         cacheValue = new EventDescriptorCollection(eventArray, true);
2823                         break;
2824
2825                     default:
2826                         Debug.Fail("unknown pipeline type");
2827                         cacheValue = null;
2828                         break;
2829                 }
2830
2831                 Trace("Pipeline : Merge results being cached for {0}", instance.GetType().Name);
2832                 cache[_pipelineMergeKeys[pipelineType]] = cacheValue;
2833                 cache.Remove(_pipelineFilterKeys[pipelineType]);
2834                 cache.Remove(_pipelineAttributeFilterKeys[pipelineType]);
2835             }
2836
2837             return list;
2838         }
2839
2840         private static void RaiseRefresh(object component) {
2841             // This volatility prevents the JIT from making certain optimizations 
2842             // that could cause this firing pattern to break. Although the likelihood 
2843             // the JIT makes those changes is mostly theoretical
2844             RefreshEventHandler handler = Volatile.Read(ref Refreshed);
2845             
2846             if (handler != null) 
2847             {
2848                 handler(new RefreshEventArgs(component));
2849             }
2850         }
2851
2852         private static void RaiseRefresh(Type type) {
2853             RefreshEventHandler handler = Volatile.Read(ref Refreshed);
2854             
2855             if (handler != null) 
2856             {
2857                 handler(new RefreshEventArgs(type));
2858             }
2859         }
2860
2861         /// <devdoc>
2862         ///    Clears the properties and events for the specified 
2863         ///    component from the cache.
2864         /// </devdoc>
2865         public static void Refresh(object component) 
2866         {
2867             Refresh(component, true);
2868         }
2869
2870         private static void Refresh(object component, bool refreshReflectionProvider) {
2871             #if DEBUG
2872             DebugTypeDescriptor.Refresh(component);
2873             #endif
2874
2875             if (component == null) 
2876             {
2877                 Debug.Fail("COMPAT:  Returning, but you should not pass null here");
2878                 return;
2879             }
2880
2881             // Build up a list of type description providers for
2882             // each type that is a derived type of the given
2883             // object.  We will invalidate the metadata at
2884             // each of these levels.
2885             bool found = false;
2886
2887             if (refreshReflectionProvider)
2888             {
2889                 Type type = component.GetType();
2890
2891                 lock (_providerTable)
2892                 {
2893                     // ReflectTypeDescritionProvider is only bound to object, but we
2894                     // need go to through the entire table to try to find custom
2895                     // providers.  If we find one, will clear our cache.
2896                     foreach (DictionaryEntry de in _providerTable)
2897                     {
2898                         Type nodeType = de.Key as Type;
2899                         if (nodeType != null && type.IsAssignableFrom(nodeType) || nodeType == typeof(object))
2900                         {
2901                             TypeDescriptionNode node = (TypeDescriptionNode)de.Value;
2902                             while (node != null && !(node.Provider is ReflectTypeDescriptionProvider))
2903                             {
2904                                 found = true;
2905                                 node = node.Next;
2906                             }
2907
2908                             if (node != null)
2909                             {
2910                                 ReflectTypeDescriptionProvider provider = (ReflectTypeDescriptionProvider)node.Provider;
2911                                 if (provider.IsPopulated(type))
2912                                 {
2913                                     found = true;
2914                                     provider.Refresh(type);
2915                                 }
2916                             }
2917                         }
2918                     }
2919                 }
2920             }
2921
2922             // We need to clear our filter even if no typedescriptionprovider had data.
2923             // This is because if you call Refresh(instance1) and Refresh(instance2)
2924             // and instance1 and instance2 are of the same type, you will end up not
2925             // actually deleting the dictionary cache on instance2 if you skip this
2926             // when you don't find a typedescriptionprovider.
2927             // However, we do not need to fire the event if we did not find any loaded
2928             // typedescriptionprovider AND the cache is empty (if someone repeatedly calls
2929             // Refresh on an instance).
2930
2931             // Now, clear any cached data for the instance.
2932             //
2933             IDictionary cache = GetCache(component);
2934             if (found || cache!= null)
2935             {
2936                 if (cache != null)
2937                 {
2938                     Trace("Pipeline : Refresh clearing all pipeline caches");
2939                     for (int idx = 0; idx < _pipelineFilterKeys.Length; idx++)
2940                     {
2941                         cache.Remove(_pipelineFilterKeys[idx]);
2942                         cache.Remove(_pipelineMergeKeys[idx]);
2943                         cache.Remove(_pipelineAttributeFilterKeys[idx]);
2944                     }
2945
2946                 }
2947
2948                 Interlocked.Increment(ref _metadataVersion);
2949
2950                 // And raise the event.
2951                 //
2952                 RaiseRefresh(component);
2953             }
2954         }
2955
2956         /// <devdoc>
2957         ///    Clears the properties and events for the specified type 
2958         ///    of component from the cache.
2959         /// </devdoc>
2960         public static void Refresh(Type type) 
2961         {
2962             #if DEBUG
2963             DebugTypeDescriptor.Refresh(type);
2964             #endif
2965             
2966             if (type == null) 
2967             {
2968                 Debug.Fail("COMPAT:  Returning, but you should not pass null here");
2969                 return;
2970             }
2971
2972             // Build up a list of type description providers for
2973             // each type that is a derived type of the given
2974             // type.  We will invalidate the metadata at
2975             // each of these levels.
2976             
2977             bool found = false;
2978
2979             lock(_providerTable)
2980             {
2981                 // ReflectTypeDescritionProvider is only bound to object, but we
2982                 // need go to through the entire table to try to find custom
2983                 // providers.  If we find one, will clear our cache.
2984                 foreach(DictionaryEntry de in _providerTable)
2985                 {
2986                     Type nodeType = de.Key as Type;
2987                     if (nodeType != null && type.IsAssignableFrom(nodeType) || nodeType == typeof(object))
2988                     {
2989                         TypeDescriptionNode node = (TypeDescriptionNode)de.Value;
2990                         while(node != null && !(node.Provider is ReflectTypeDescriptionProvider))
2991                         {
2992                             found = true;
2993                             node = node.Next;
2994                         }
2995
2996                         if (node != null)
2997                         {
2998                             ReflectTypeDescriptionProvider provider = (ReflectTypeDescriptionProvider)node.Provider;
2999                             if (provider.IsPopulated(type))
3000                             {
3001                                 found = true;
3002                                 provider.Refresh(type);
3003                             }
3004                         }
3005                     }
3006                 }
3007             }
3008
3009             // We only clear our filter and fire the refresh event if there was one or
3010             // more type description providers that were populated with metdata.
3011             // This prevents us from doing a lot of extra work and raising 
3012             // a ton more events than we need to.
3013             //
3014             if (found)
3015             {
3016                 Interlocked.Increment(ref _metadataVersion);
3017
3018                 // And raise the event.
3019                 //
3020                 RaiseRefresh(type);
3021             }
3022         }
3023
3024         /// <devdoc>
3025         ///    Clears the properties and events for the specified 
3026         ///    module from the cache.
3027         /// </devdoc>
3028         public static void Refresh(Module module) 
3029         {
3030             #if DEBUG
3031             DebugTypeDescriptor.Refresh(module);
3032             #endif
3033             
3034             if (module == null) 
3035             {
3036                 Debug.Fail("COMPAT:  Returning, but you should not pass null here");
3037                 return;
3038             }
3039
3040             // Build up a list of type description providers for
3041             // each type that is a derived type of the given
3042             // object.  We will invalidate the metadata at
3043             // each of these levels.
3044             Hashtable refreshedTypes = null;
3045
3046             lock(_providerTable)
3047             {
3048                 foreach(DictionaryEntry de in _providerTable)
3049                 {
3050                     Type nodeType = de.Key as Type;
3051                     if (nodeType != null && nodeType.Module.Equals(module) || nodeType == typeof(object))
3052                     {
3053                         TypeDescriptionNode node = (TypeDescriptionNode)de.Value;
3054                         while(node != null && !(node.Provider is ReflectTypeDescriptionProvider))
3055                         {
3056                             if (refreshedTypes == null) {
3057                                 refreshedTypes = new Hashtable();
3058                             }
3059                             refreshedTypes[nodeType] = nodeType;
3060                             node = node.Next;
3061                         }
3062
3063                         if (node != null)
3064                         {
3065                             ReflectTypeDescriptionProvider provider = (ReflectTypeDescriptionProvider)node.Provider;
3066                             Type[] populatedTypes = provider.GetPopulatedTypes(module);
3067
3068                             foreach(Type populatedType in populatedTypes) {
3069                                 provider.Refresh(populatedType);
3070                                 if (refreshedTypes == null) {
3071                                     refreshedTypes = new Hashtable();
3072                                 }
3073                                 refreshedTypes[populatedType] = populatedType;
3074                             }
3075                         }
3076                     }
3077                 }
3078             }
3079
3080             // And raise the event if types were refresh and handlers are attached.
3081             //
3082             if (refreshedTypes != null && Refreshed != null) 
3083             {
3084                 foreach(Type t in refreshedTypes.Keys) {
3085                     RaiseRefresh(t);
3086                 }
3087             }
3088         }
3089         
3090         /// <devdoc>
3091         ///    Clears the properties and events for the specified 
3092         ///    assembly from the cache.
3093         /// </devdoc>
3094         [ResourceExposure(ResourceScope.None)]
3095         [ResourceConsumption(ResourceScope.Machine | ResourceScope.Assembly, ResourceScope.Machine | ResourceScope.Assembly)]
3096         public static void Refresh(Assembly assembly) 
3097         {
3098             if (assembly == null) 
3099             {
3100                 Debug.Fail("COMPAT:  Returning, but you should not pass null here");
3101                 return;
3102             }
3103
3104             foreach (Module mod in assembly.GetModules()) 
3105             {
3106                 Refresh(mod);
3107             }
3108
3109             // Debug type descriptor has the same code, so our call above will handle this.
3110         }
3111
3112         /// <devdoc>
3113         ///     The RemoveAssociation method removes an association with an object.  
3114         /// </devdoc>
3115         [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
3116         [EditorBrowsable(EditorBrowsableState.Advanced)]
3117         public static void RemoveAssociation(object primary, object secondary)
3118         {
3119             if (primary == null)
3120             {
3121                 throw new ArgumentNullException("primary");
3122             }
3123
3124             if (secondary == null)
3125             {
3126                 throw new ArgumentNullException("secondary");
3127             }
3128
3129             Hashtable assocTable = _associationTable;
3130             if (assocTable != null)
3131             {
3132                 IList associations = (IList)assocTable[primary];
3133                 if (associations != null)
3134                 {
3135                     lock(associations)
3136                     {
3137                         for (int idx = associations.Count - 1; idx >= 0; idx--)
3138                         {
3139                             // Look for an associated object that has a type that
3140                             // matches the given type.
3141                             //
3142                             WeakReference weakRef = (WeakReference)associations[idx];
3143                             object secondaryItem = weakRef.Target;
3144                             if (secondaryItem == null || secondaryItem == secondary)
3145                             {
3146                                 associations.RemoveAt(idx);
3147                             }
3148                         }
3149                     }
3150                 }
3151             }
3152         }
3153
3154         /// <devdoc>
3155         ///     The RemoveAssociations method removes all associations for a primary object.
3156         /// </devdoc>
3157         [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
3158         [EditorBrowsable(EditorBrowsableState.Advanced)]
3159         public static void RemoveAssociations(object primary)
3160         {
3161             if (primary == null)
3162             {
3163                 throw new ArgumentNullException("primary");
3164             }
3165
3166             Hashtable assocTable = _associationTable;
3167             if (assocTable != null)
3168             {
3169                 assocTable.Remove(primary);
3170             }
3171         }
3172
3173         /// <devdoc>
3174         ///     The RemoveProvider method removes a previously added type 
3175         ///     description provider.  Removing a provider causes a Refresh 
3176         ///     event to be raised for the object or type the provider is 
3177         ///     associated with.
3178         /// </devdoc>
3179         [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
3180         [EditorBrowsable(EditorBrowsableState.Advanced)]
3181         public static void RemoveProvider(TypeDescriptionProvider provider, Type type)
3182         {
3183             if (provider == null)
3184             {
3185                 throw new ArgumentNullException("provider");
3186             }
3187
3188             if (type == null)
3189             {
3190                 throw new ArgumentNullException("type");
3191             }
3192
3193             // Walk the nodes until we find the right one, and then remove it.
3194             NodeRemove(type, provider);
3195             RaiseRefresh(type);
3196         }
3197         
3198         /// <devdoc>
3199         ///     The RemoveProvider method removes a previously added type 
3200         ///     description provider.  Removing a provider causes a Refresh 
3201         ///     event to be raised for the object or type the provider is 
3202         ///     associated with.
3203         /// </devdoc>
3204         [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
3205         [EditorBrowsable(EditorBrowsableState.Advanced)]
3206         public static void RemoveProvider(TypeDescriptionProvider provider, object instance)
3207         {
3208             if (provider == null)
3209             {
3210                 throw new ArgumentNullException("provider");
3211             }
3212
3213             if (instance == null)
3214             {
3215                 throw new ArgumentNullException("instance");
3216             }
3217
3218             // Walk the nodes until we find the right one, and then remove it.
3219             NodeRemove(instance, provider);
3220             RaiseRefresh(instance);
3221         }
3222
3223
3224         /// <devdoc>
3225         ///     The RemoveProvider method removes a previously added type 
3226         ///     description provider.  Removing a provider causes a Refresh 
3227         ///     event to be raised for the object or type the provider is 
3228         ///     associated with.
3229         ///     
3230         ///     This method can be called from partially trusted code. If 
3231         ///     <see cref="TypeDescriptorPermissionFlags.RestrictedRegistrationAccess"/>
3232         ///     is defined, the caller can unregister a provider for the specified type
3233         ///     if it's also partially trusted.
3234         /// </devdoc>
3235         [EditorBrowsable(EditorBrowsableState.Advanced)]
3236         public static void RemoveProviderTransparent(TypeDescriptionProvider provider, Type type)
3237         {
3238             if (provider == null)
3239             {
3240                 throw new ArgumentNullException("provider");
3241             }
3242
3243             if (type == null)
3244             {
3245                 throw new ArgumentNullException("type");
3246             }
3247 #if FEATURE_MONO_CAS
3248             PermissionSet typeDescriptorPermission = new PermissionSet(PermissionState.None);
3249             typeDescriptorPermission.AddPermission(new TypeDescriptorPermission(TypeDescriptorPermissionFlags.RestrictedRegistrationAccess));
3250
3251             PermissionSet targetPermissions = type.Assembly.PermissionSet;
3252             targetPermissions = targetPermissions.Union(typeDescriptorPermission);
3253
3254             targetPermissions.Demand();
3255 #endif
3256             RemoveProvider(provider, type);
3257         }
3258
3259         /// <devdoc>
3260         ///     The RemoveProvider method removes a previously added type 
3261         ///     description provider.  Removing a provider causes a Refresh 
3262         ///     event to be raised for the object or type the provider is 
3263         ///     associated with.
3264         ///     
3265         ///     This method can be called from partially trusted code. If 
3266         ///     <see cref="TypeDescriptorPermissionFlags.RestrictedRegistrationAccess"/>
3267         ///     is defined, the caller can register a provider for the specified instance 
3268         ///     if its type is also partially trusted.
3269         /// </devdoc>
3270         [EditorBrowsable(EditorBrowsableState.Advanced)]
3271         public static void RemoveProviderTransparent(TypeDescriptionProvider provider, object instance)
3272         {
3273             if (provider == null)
3274             {
3275                 throw new ArgumentNullException("provider");
3276             }
3277
3278             if (instance == null)
3279             {
3280                 throw new ArgumentNullException("instance");
3281             }
3282 #if FEATURE_MONO_CAS
3283             Type type = instance.GetType();
3284
3285             PermissionSet typeDescriptorPermission = new PermissionSet(PermissionState.None);
3286             typeDescriptorPermission.AddPermission(new TypeDescriptorPermission(TypeDescriptorPermissionFlags.RestrictedRegistrationAccess));
3287
3288             PermissionSet targetPermissions = type.Assembly.PermissionSet;
3289             targetPermissions = targetPermissions.Union(typeDescriptorPermission);
3290
3291             targetPermissions.Demand();
3292 #endif
3293             RemoveProvider(provider, instance);
3294         }
3295
3296         /// <devdoc> 
3297         ///     This function takes a member descriptor and an attribute and determines whether 
3298         ///     the member satisfies the particular attribute.  This either means that the member 
3299         ///     contains the attribute or the member does not contain the attribute and the default 
3300         ///     for the attribute matches the passed in attribute. 
3301         /// </devdoc> 
3302         private static bool ShouldHideMember(MemberDescriptor member, Attribute attribute) 
3303         {
3304             if (member == null || attribute == null) 
3305             {
3306                 return true;
3307             }
3308
3309             Attribute memberAttribute = member.Attributes[attribute.GetType()];
3310             if (memberAttribute == null)
3311             {
3312                 return !attribute.IsDefaultAttribute();
3313             }
3314             else 
3315             {
3316                 return !(attribute.Match(memberAttribute));
3317             }
3318         }
3319
3320         /// <devdoc>
3321         ///     Sorts descriptors by name of the descriptor.
3322         /// </devdoc>
3323         public static void SortDescriptorArray(IList infos) 
3324         {
3325             if (infos == null)
3326             {
3327                 throw new ArgumentNullException("infos");
3328             }
3329
3330             ArrayList.Adapter(infos).Sort(MemberDescriptorComparer.Instance);
3331         }
3332
3333         /// <devdoc>
3334         ///     Internal tracing API for debugging type descriptor.
3335         /// </devdoc>
3336         [Conditional("DEBUG")]
3337         internal static void Trace(string message, params object[] args)
3338         {
3339             Debug.WriteLineIf(TraceDescriptor.Enabled, string.Format(CultureInfo.InvariantCulture, "TypeDescriptor : {0}", string.Format(CultureInfo.InvariantCulture, message, args)));
3340         }
3341
3342         /// <devdoc>
3343         ///     This is a type description provider that adds the given
3344         ///     array of attributes to a class or instance, preserving the rest
3345         ///     of the metadata in the process.
3346         /// </devdoc>
3347         private sealed class AttributeProvider : TypeDescriptionProvider
3348         {
3349             Attribute[] _attrs;
3350
3351             /// <devdoc>
3352             ///     Creates a new attribute provider.
3353             /// </devdoc>
3354             internal AttributeProvider(TypeDescriptionProvider existingProvider, params Attribute[] attrs) : base(existingProvider)
3355             {
3356                 _attrs = attrs;
3357             }
3358
3359             /// <devdoc>
3360             ///     Creates a custom type descriptor that replaces the attributes.
3361             /// </devdoc>
3362             public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
3363             {
3364                 return new AttributeTypeDescriptor(_attrs, base.GetTypeDescriptor(objectType, instance));
3365             }
3366
3367             /// <devdoc>
3368             ///     Our custom type descriptor.
3369             /// </devdoc>
3370             private class AttributeTypeDescriptor : CustomTypeDescriptor
3371             {
3372                 Attribute[]         _attributeArray;
3373
3374                 /// <devdoc>
3375                 ///     Creates a new custom type descriptor that can merge 
3376                 ///     the provided set of attributes with the existing set.
3377                 /// </devdoc>
3378                 internal AttributeTypeDescriptor(Attribute[] attrs, ICustomTypeDescriptor parent) : base(parent)
3379                 {
3380                     _attributeArray = attrs;
3381                 }
3382
3383                 /// <devdoc>
3384                 ///     Retrieves the merged set of attributes.  We do not cache
3385                 ///     this because there is always the possibility that someone
3386                 ///     changed our parent provider's metadata.  TypeDescriptor
3387                 ///     will cache this for us anyhow.
3388                 /// </devdoc>
3389                 public override AttributeCollection GetAttributes()
3390                 {
3391                     Attribute[] finalAttr = null;
3392                     AttributeCollection existing = base.GetAttributes();
3393                     Attribute[] newAttrs = _attributeArray;
3394                     Attribute[] newArray = new Attribute[existing.Count + newAttrs.Length];
3395                     int actualCount = existing.Count;
3396                     existing.CopyTo(newArray, 0);
3397
3398                     for (int idx = 0; idx < newAttrs.Length; idx++)
3399                     {
3400
3401                         Debug.Assert(newAttrs[idx] != null, "_attributes contains a null member");
3402                         
3403                         // We must see if this attribute is already in the existing
3404                         // array.  If it is, we replace it.
3405                         bool match = false;
3406                         for (int existingIdx = 0; existingIdx < existing.Count; existingIdx++)
3407                         {
3408                             if (newArray[existingIdx].TypeId.Equals(newAttrs[idx].TypeId))
3409                             {
3410                                 match = true;
3411                                 newArray[existingIdx] = newAttrs[idx];
3412                                 break;
3413                             }
3414                         }
3415
3416                         if (!match)
3417                         {
3418                             newArray[actualCount++] = newAttrs[idx];
3419                         }
3420                     }
3421
3422                     // Now, if we collapsed some attributes, create a new array.
3423                     //
3424                     if (actualCount < newArray.Length)
3425                     {
3426                         finalAttr = new Attribute[actualCount];
3427                         Array.Copy(newArray, 0, finalAttr, 0, actualCount);
3428                     }
3429                     else
3430                     {
3431                         finalAttr= newArray;
3432                     }
3433
3434                     return new AttributeCollection(finalAttr);
3435                 }
3436             }
3437         }
3438
3439         /// <devdoc>
3440         ///     This class is a type description provider that works with the IComNativeDescriptorHandler
3441         ///     interface.
3442         /// </devdoc>
3443         private sealed class ComNativeDescriptionProvider : TypeDescriptionProvider
3444         {
3445 #pragma warning disable 618
3446             private IComNativeDescriptorHandler _handler;
3447
3448             internal ComNativeDescriptionProvider(IComNativeDescriptorHandler handler)
3449             {
3450                 _handler = handler;
3451             }
3452
3453             /// <devdoc>
3454             ///     Returns the COM handler object.
3455             /// </devdoc>
3456             internal IComNativeDescriptorHandler Handler
3457             {
3458                 get
3459                 {
3460                     return _handler;
3461                 }
3462                 set
3463                 {
3464                     _handler = value;
3465                 }
3466             }
3467 #pragma warning restore 618
3468             
3469             /// <devdoc>
3470             ///     Implements GetTypeDescriptor.  This creates a custom type
3471             ///     descriptor that walks the linked list for each of its calls.
3472             /// </devdoc>
3473             
3474             [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters")]
3475             public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
3476             {
3477                 if (objectType == null)
3478                 {
3479                     throw new ArgumentNullException("objectType");
3480                 }
3481
3482                 if (instance == null)
3483                 {
3484                     return null;
3485                 }
3486
3487                 if (!objectType.IsInstanceOfType(instance))
3488                 {
3489                     throw new ArgumentException("instance");
3490                 }
3491
3492                 return new ComNativeTypeDescriptor(_handler, instance);
3493             }
3494
3495             /// <devdoc>
3496             ///     This type descriptor sits on top of a native
3497             ///     descriptor handler.
3498             /// </devdoc>
3499             private sealed class ComNativeTypeDescriptor : ICustomTypeDescriptor
3500             {
3501 #pragma warning disable 618
3502                 private IComNativeDescriptorHandler _handler;
3503                 private object _instance;
3504
3505                 /// <devdoc>
3506                 ///     Creates a new ComNativeTypeDescriptor.
3507                 /// </devdoc>
3508                 internal ComNativeTypeDescriptor(IComNativeDescriptorHandler handler, object instance)
3509                 {
3510                     _handler = handler;
3511                     _instance = instance;
3512                 }
3513 #pragma warning restore 618
3514
3515                 /// <devdoc>
3516                 ///     ICustomTypeDescriptor implementation.
3517                 /// </devdoc>
3518                 AttributeCollection ICustomTypeDescriptor.GetAttributes()
3519                 {
3520                     return _handler.GetAttributes(_instance);
3521                 }
3522
3523                 /// <devdoc>
3524                 ///     ICustomTypeDescriptor implementation.
3525                 /// </devdoc>
3526                 string ICustomTypeDescriptor.GetClassName()
3527                 {
3528                     return _handler.GetClassName(_instance);
3529                 }
3530
3531                 /// <devdoc>
3532                 ///     ICustomTypeDescriptor implementation.
3533                 /// </devdoc>
3534                 string ICustomTypeDescriptor.GetComponentName()
3535                 {
3536                     return null;
3537                 }
3538
3539                 /// <devdoc>
3540                 ///     ICustomTypeDescriptor implementation.
3541                 /// </devdoc>
3542                 TypeConverter ICustomTypeDescriptor.GetConverter()
3543                 {
3544                     return _handler.GetConverter(_instance);
3545                 }
3546
3547                 /// <devdoc>
3548                 ///     ICustomTypeDescriptor implementation.
3549                 /// </devdoc>
3550                 EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
3551                 {
3552                     return _handler.GetDefaultEvent(_instance);
3553                 }
3554
3555                 /// <devdoc>
3556                 ///     ICustomTypeDescriptor implementation.
3557                 /// </devdoc>
3558                 PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
3559                 {
3560                     return _handler.GetDefaultProperty(_instance);
3561                 }
3562
3563                 /// <devdoc>
3564                 ///     ICustomTypeDescriptor implementation.
3565                 /// </devdoc>
3566                 object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
3567                 {
3568                     return _handler.GetEditor(_instance, editorBaseType);
3569                 }
3570
3571                 /// <devdoc>
3572                 ///     ICustomTypeDescriptor implementation.
3573                 /// </devdoc>
3574                 EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
3575                 {
3576                     return _handler.GetEvents(_instance);
3577                 }
3578
3579                 /// <devdoc>
3580                 ///     ICustomTypeDescriptor implementation.
3581                 /// </devdoc>
3582                 EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
3583                 {
3584                     return _handler.GetEvents(_instance, attributes);
3585                 }
3586
3587                 /// <devdoc>
3588                 ///     ICustomTypeDescriptor implementation.
3589                 /// </devdoc>
3590                 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
3591                 {
3592                     return _handler.GetProperties(_instance, null);
3593                 }
3594
3595                 /// <devdoc>
3596                 ///     ICustomTypeDescriptor implementation.
3597                 /// </devdoc>
3598                 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
3599                 {
3600                     return _handler.GetProperties(_instance, attributes);
3601                 }
3602
3603                 /// <devdoc>
3604                 ///     ICustomTypeDescriptor implementation.
3605                 /// </devdoc>
3606                 object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
3607                 {
3608                     return _instance;
3609                 }
3610             }
3611         }
3612
3613         /// <devdoc>
3614         ///     This is a simple class that is used to store a filtered
3615         ///     set of members in an object's dictionary cache.  It is
3616         ///     used by the PipelineAttributeFilter method.
3617         /// </devdoc>
3618         private sealed class AttributeFilterCacheItem
3619         {
3620             private Attribute[] _filter;
3621             internal ICollection FilteredMembers;
3622
3623             internal AttributeFilterCacheItem(Attribute[] filter, ICollection filteredMembers)
3624             {
3625                 _filter = filter;
3626                 FilteredMembers = filteredMembers;
3627             }
3628
3629             internal bool IsValid(Attribute[] filter)
3630             {
3631                 if (_filter.Length != filter.Length) return false;
3632                 
3633                 for (int idx = 0; idx < filter.Length; idx++) {
3634                     if (_filter[idx] != filter[idx]) {
3635                         return false;
3636                     }
3637                 }
3638                 
3639                 return true;
3640             }
3641         }
3642
3643         /// <devdoc>
3644         /// This small class contains cache information for the filter stage of our
3645         /// caching algorithm.  It is used by the PipelineFilter method.
3646         /// </devdoc>
3647         private sealed class FilterCacheItem {
3648             private ITypeDescriptorFilterService _filterService;
3649             internal ICollection FilteredMembers;
3650
3651             internal FilterCacheItem(ITypeDescriptorFilterService filterService, ICollection filteredMembers) {
3652                 _filterService = filterService;
3653                 FilteredMembers = filteredMembers;
3654             }
3655
3656             internal bool IsValid(ITypeDescriptorFilterService filterService) {
3657                 if (!Object.ReferenceEquals(_filterService, filterService)) return false;
3658                 return true;
3659             }
3660         }
3661
3662         /// <devdoc>
3663         ///     An unimplemented interface.  What is this?  It is an interface that nobody ever
3664         ///     implements, of course? Where and why would it be used?  Why, to find cross-process
3665         ///     remoted objects, of course!  If a well-known object comes in from a cross process
3666         ///     connection, the remoting layer does contain enough type information to determine
3667         ///     if an object implements an interface.  It assumes that if you are going to cast
3668         ///     an object to an interface that you know what you're doing, and allows the cast,
3669         ///     even for objects that DON'T actually implement the interface.  The error here
3670         ///     is raised later when you make your first call on that interface pointer:  you
3671         ///     get a remoting exception.
3672         ///
3673         ///     This is a big problem for code that does "is" and "as" checks to detect the
3674         ///     presence of an interface.  We do that all over the place here, so we do a check
3675         ///     during parameter validation to see if an object implements IUnimplemented.  If it
3676         ///     does, we know that what we really have is a lying remoting proxy, and we bail.
3677         /// </devdoc>
3678         private interface IUnimplemented {}
3679
3680         /// <devdoc>
3681         ///     This comparer compares member descriptors for sorting.
3682         /// </devdoc>
3683         private sealed class MemberDescriptorComparer : IComparer {
3684             public static readonly MemberDescriptorComparer Instance = new MemberDescriptorComparer();
3685
3686             public int Compare(object left, object right) {
3687                 return string.Compare(((MemberDescriptor)left).Name, ((MemberDescriptor)right).Name, false, CultureInfo.InvariantCulture);
3688             }
3689         }
3690
3691         /// <devdoc>
3692         ///     This is a merged type descriptor that can merge the output of
3693         ///     a primary and secondary type descriptor.  If the primary doesn't
3694         ///     provide the needed information, the request is passed on to the 
3695         ///     secondary.
3696         /// </devdoc>
3697         private sealed class MergedTypeDescriptor : ICustomTypeDescriptor
3698         {
3699             private ICustomTypeDescriptor _primary;
3700             private ICustomTypeDescriptor _secondary;
3701
3702             /// <devdoc>
3703             ///     Creates a new MergedTypeDescriptor.
3704             /// </devdoc>
3705             internal MergedTypeDescriptor(ICustomTypeDescriptor primary, ICustomTypeDescriptor secondary)
3706             {
3707                 _primary = primary;
3708                 _secondary = secondary;
3709             }
3710
3711             /// <devdoc>
3712             ///     ICustomTypeDescriptor implementation.
3713             /// </devdoc>
3714             AttributeCollection ICustomTypeDescriptor.GetAttributes()
3715             {
3716                 AttributeCollection attrs = _primary.GetAttributes();
3717                 if (attrs == null)
3718                 {
3719                     attrs = _secondary.GetAttributes();
3720                 }
3721
3722                 Debug.Assert(attrs != null, "Someone should have handled this");
3723                 return attrs;
3724             }
3725
3726             /// <devdoc>
3727             ///     ICustomTypeDescriptor implementation.
3728             /// </devdoc>
3729             string ICustomTypeDescriptor.GetClassName()
3730             {
3731                 string className = _primary.GetClassName();
3732                 if (className == null)
3733                 {
3734                     className = _secondary.GetClassName();
3735                 }
3736
3737                 Debug.Assert(className != null, "Someone should have handled this");
3738                 return className;
3739             }
3740
3741             /// <devdoc>
3742             ///     ICustomTypeDescriptor implementation.
3743             /// </devdoc>
3744             string ICustomTypeDescriptor.GetComponentName()
3745             {
3746                 string name = _primary.GetComponentName();
3747                 if (name == null)
3748                 {
3749                     name = _secondary.GetComponentName();
3750                 }
3751
3752                 return name;
3753             }
3754
3755             /// <devdoc>
3756             ///     ICustomTypeDescriptor implementation.
3757             /// </devdoc>
3758             TypeConverter ICustomTypeDescriptor.GetConverter()
3759             {
3760                 TypeConverter converter = _primary.GetConverter();
3761                 if (converter == null)
3762                 {
3763                     converter = _secondary.GetConverter();
3764                 }
3765
3766                 Debug.Assert(converter != null, "Someone should have handled this");
3767                 return converter;
3768             }
3769
3770             /// <devdoc>
3771             ///     ICustomTypeDescriptor implementation.
3772             /// </devdoc>
3773             EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
3774             {
3775                 EventDescriptor evt = _primary.GetDefaultEvent();
3776                 if (evt == null)
3777                 {
3778                     evt = _secondary.GetDefaultEvent();
3779                 }
3780
3781                 return evt;
3782             }
3783
3784             /// <devdoc>
3785             ///     ICustomTypeDescriptor implementation.
3786             /// </devdoc>
3787             PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
3788             {
3789                 PropertyDescriptor prop = _primary.GetDefaultProperty();
3790                 if (prop == null)
3791                 {
3792                     prop = _secondary.GetDefaultProperty();
3793                 }
3794
3795                 return prop;
3796             }
3797
3798             /// <devdoc>
3799             ///     ICustomTypeDescriptor implementation.
3800             /// </devdoc>
3801             object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
3802             {
3803                 if (editorBaseType == null)
3804                 {
3805                     throw new ArgumentNullException("editorBaseType");
3806                 }
3807
3808                 object editor = _primary.GetEditor(editorBaseType);
3809                 if (editor == null)
3810                 {
3811                     editor = _secondary.GetEditor(editorBaseType);
3812                 }
3813
3814                 return editor;
3815             }
3816
3817             /// <devdoc>
3818             ///     ICustomTypeDescriptor implementation.
3819             /// </devdoc>
3820             EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
3821             {
3822                 EventDescriptorCollection events = _primary.GetEvents();
3823                 if (events == null)
3824                 {
3825                     events = _secondary.GetEvents();
3826                 }
3827
3828                 Debug.Assert(events != null, "Someone should have handled this");
3829                 return events;
3830             }
3831
3832             /// <devdoc>
3833             ///     ICustomTypeDescriptor implementation.
3834             /// </devdoc>
3835             EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
3836             {
3837                 EventDescriptorCollection events = _primary.GetEvents(attributes);
3838                 if (events == null)
3839                 {
3840                     events = _secondary.GetEvents(attributes);
3841                 }
3842
3843                 Debug.Assert(events != null, "Someone should have handled this");
3844                 return events;
3845             }
3846
3847             /// <devdoc>
3848             ///     ICustomTypeDescriptor implementation.
3849             /// </devdoc>
3850             PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
3851             {
3852                 PropertyDescriptorCollection properties = _primary.GetProperties();
3853                 if (properties == null)
3854                 {
3855                     properties = _secondary.GetProperties();
3856                 }
3857
3858                 Debug.Assert(properties != null, "Someone should have handled this");
3859                 return properties;
3860             }
3861
3862             /// <devdoc>
3863             ///     ICustomTypeDescriptor implementation.
3864             /// </devdoc>
3865             PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
3866             {
3867                 PropertyDescriptorCollection properties = _primary.GetProperties(attributes);
3868                 if (properties == null)
3869                 {
3870                     properties = _secondary.GetProperties(attributes);
3871                 }
3872
3873                 Debug.Assert(properties != null, "Someone should have handled this");
3874                 return properties;
3875             }
3876
3877             /// <devdoc>
3878             ///     ICustomTypeDescriptor implementation.
3879             /// </devdoc>
3880             object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
3881             {
3882                 object owner = _primary.GetPropertyOwner(pd);
3883                 if (owner == null)
3884                 {
3885                     owner = _secondary.GetPropertyOwner(pd);
3886                 }
3887
3888                 return owner;
3889             }
3890         }
3891
3892         /// <devdoc>
3893         ///     This is a linked list node that is comprised of a type
3894         ///     description provider.  Each node contains a Next pointer
3895         ///     to the next node in the list and also a Provider pointer
3896         ///     which contains the type description provider this node
3897         ///     represents.  The implementation of TypeDescriptionProvider
3898         ///     that the node provides simply invokes the corresponding
3899         ///     method on the node's provider.
3900         /// </devdoc>
3901         private sealed class TypeDescriptionNode : TypeDescriptionProvider
3902         {
3903             internal TypeDescriptionNode                Next;
3904             internal TypeDescriptionProvider   Provider;
3905
3906             /// <devdoc>
3907             ///     Creates a new type description node.
3908             /// </devdoc>
3909             internal TypeDescriptionNode(TypeDescriptionProvider provider)
3910             {
3911                 Provider = provider;
3912             }
3913
3914             /// <devdoc>
3915             ///     Implements CreateInstance.  This just walks the linked list
3916             ///     looking for someone who implements the call.
3917             /// </devdoc>
3918             public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)
3919             {
3920                 if (objectType == null)
3921                 {
3922                     throw new ArgumentNullException("objectType");
3923                 }
3924
3925                 if (argTypes != null)
3926                 {
3927                     if (args == null)
3928                     {
3929                         throw new ArgumentNullException("args");
3930                     }
3931
3932                     if (argTypes.Length != args.Length)
3933                     {
3934                         throw new ArgumentException(SR.GetString(SR.TypeDescriptorArgsCountMismatch));
3935                     }
3936                 }
3937
3938                 return Provider.CreateInstance(provider, objectType, argTypes, args);
3939             }
3940
3941             /// <devdoc>
3942             ///     Implements GetCache.  This just walks the linked
3943             ///     list looking for someone who implements the call.
3944             /// </devdoc>
3945             public override IDictionary GetCache(object instance)
3946             {
3947                 if (instance == null)
3948                 {
3949                     throw new ArgumentNullException("instance");
3950                 }
3951
3952                 return Provider.GetCache(instance);
3953             }
3954
3955             /// <devdoc>
3956             ///     Implements GetExtendedTypeDescriptor.  This creates a custom type
3957             ///     descriptor that walks the linked list for each of its calls.
3958             /// </devdoc>
3959             public override ICustomTypeDescriptor GetExtendedTypeDescriptor(object instance)
3960             {
3961                 if (instance == null)
3962                 {
3963                     throw new ArgumentNullException("instance");
3964                 }
3965
3966                 return new DefaultExtendedTypeDescriptor(this, instance);
3967             }
3968
3969             protected internal override IExtenderProvider[] GetExtenderProviders(object instance)
3970             {
3971                 if (instance == null)
3972                 {
3973                     throw new ArgumentNullException("instance");
3974                 }
3975
3976                 return Provider.GetExtenderProviders(instance);
3977             }
3978
3979             /// <devdoc>
3980             ///     The name of the specified component, or null if the component has no name.
3981             ///     In many cases this will return the same value as GetComponentName. If the
3982             ///     component resides in a nested container or has other nested semantics, it may
3983             ///     return a different fully qualfied name.
3984             ///
3985             ///     If not overridden, the default implementation of this method will call
3986             ///     GetTypeDescriptor.GetComponentName.
3987             /// </devdoc>
3988             public override string GetFullComponentName(object component) 
3989             {
3990                 if (component == null)
3991                 {
3992                     throw new ArgumentNullException("component");
3993                 }
3994
3995                 return Provider.GetFullComponentName(component);
3996             }
3997
3998             /// <devdoc>
3999             ///     Implements GetReflectionType.  This just walks the linked list
4000             ///     looking for someone who implements the call.
4001             /// </devdoc>
4002             public override Type GetReflectionType(Type objectType, object instance)
4003             {
4004                 if (objectType == null)
4005                 {
4006                     throw new ArgumentNullException("objectType");
4007                 }
4008
4009                 return Provider.GetReflectionType(objectType, instance);
4010             }
4011
4012             public override Type GetRuntimeType(Type objectType)
4013             {
4014                 if (objectType == null)
4015                 {
4016                     throw new ArgumentNullException("objectType");
4017                 }
4018
4019                 return Provider.GetRuntimeType(objectType);
4020             }
4021
4022             /// <devdoc>
4023             ///     Implements GetTypeDescriptor.  This creates a custom type
4024             ///     descriptor that walks the linked list for each of its calls.
4025             /// </devdoc>
4026
4027             [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters")]
4028             public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
4029             {
4030                 if (objectType == null)
4031                 {
4032                     throw new ArgumentNullException("objectType");
4033                 }
4034
4035                 if (instance != null && !objectType.IsInstanceOfType(instance))
4036                 {
4037                     throw new ArgumentException("instance");
4038                 }
4039
4040                 return new DefaultTypeDescriptor(this, objectType, instance);
4041             }
4042
4043             public override bool IsSupportedType(Type type)
4044             {
4045                 if (type == null)
4046                 {
4047                     throw new ArgumentNullException("type");
4048                 }
4049                 return Provider.IsSupportedType(type);
4050             }
4051
4052             /// <devdoc>
4053             ///     A type descriptor for extended types.  This type descriptor
4054             ///     looks at the head node in the linked list.
4055             /// </devdoc>
4056             private struct DefaultExtendedTypeDescriptor : ICustomTypeDescriptor
4057             {
4058                 private TypeDescriptionNode _node;
4059                 private object              _instance;
4060
4061                 /// <devdoc>
4062                 ///     Creates a new WalkingExtendedTypeDescriptor.
4063                 /// </devdoc>
4064                 internal DefaultExtendedTypeDescriptor(TypeDescriptionNode node, object instance)
4065                 {
4066                     _node = node;
4067                     _instance = instance;
4068                 }
4069
4070                 /// <devdoc>
4071                 ///     ICustomTypeDescriptor implementation.
4072                 /// </devdoc>
4073                 AttributeCollection ICustomTypeDescriptor.GetAttributes()
4074                 {
4075                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4076                     // If so, we can call on it directly rather than creating another
4077                     // custom type descriptor
4078
4079                     TypeDescriptionProvider p = _node.Provider;
4080                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4081
4082                     if (rp != null) {
4083                         return rp.GetExtendedAttributes(_instance);
4084                     }
4085
4086                     ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4087                     if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4088                     AttributeCollection attrs = desc.GetAttributes();
4089                     if (attrs == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetAttributes"));
4090                     return attrs;
4091                 }
4092
4093                 /// <devdoc>
4094                 ///     ICustomTypeDescriptor implementation.
4095                 /// </devdoc>
4096                 string ICustomTypeDescriptor.GetClassName()
4097                 {
4098                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4099                     // If so, we can call on it directly rather than creating another
4100                     // custom type descriptor
4101
4102                     TypeDescriptionProvider p = _node.Provider;
4103                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4104
4105                     if (rp != null) {
4106                         return rp.GetExtendedClassName(_instance);
4107                     }
4108
4109                     ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4110                     if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4111                     string name = desc.GetClassName();
4112                     if (name == null) name = _instance.GetType().FullName;
4113                     return name;
4114                 }
4115
4116                 /// <devdoc>
4117                 ///     ICustomTypeDescriptor implementation.
4118                 /// </devdoc>
4119                 string ICustomTypeDescriptor.GetComponentName()
4120                 {
4121                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4122                     // If so, we can call on it directly rather than creating another
4123                     // custom type descriptor
4124
4125                     TypeDescriptionProvider p = _node.Provider;
4126                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4127
4128                     if (rp != null) {
4129                         return rp.GetExtendedComponentName(_instance);
4130                     }
4131
4132                     ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4133                     if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4134                     return desc.GetComponentName();
4135                 }
4136
4137                 /// <devdoc>
4138                 ///     ICustomTypeDescriptor implementation.
4139                 /// </devdoc>
4140                 TypeConverter ICustomTypeDescriptor.GetConverter()
4141                 {
4142                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4143                     // If so, we can call on it directly rather than creating another
4144                     // custom type descriptor
4145
4146                     TypeDescriptionProvider p = _node.Provider;
4147                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4148
4149                     if (rp != null) {
4150                         return rp.GetExtendedConverter(_instance);
4151                     }
4152
4153                     ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4154                     if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4155                     TypeConverter converter = desc.GetConverter();
4156                     if (converter == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetConverter"));
4157                     return converter;
4158                 }
4159
4160                 /// <devdoc>
4161                 ///     ICustomTypeDescriptor implementation.
4162                 /// </devdoc>
4163                 EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
4164                 {
4165                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4166                     // If so, we can call on it directly rather than creating another
4167                     // custom type descriptor
4168
4169                     TypeDescriptionProvider p = _node.Provider;
4170                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4171
4172                     if (rp != null) {
4173                         return rp.GetExtendedDefaultEvent(_instance);
4174                     }
4175
4176                     ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4177                     if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4178                     return desc.GetDefaultEvent();
4179                 }
4180
4181                 /// <devdoc>
4182                 ///     ICustomTypeDescriptor implementation.
4183                 /// </devdoc>
4184                 PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
4185                 {
4186                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4187                     // If so, we can call on it directly rather than creating another
4188                     // custom type descriptor
4189
4190                     TypeDescriptionProvider p = _node.Provider;
4191                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4192
4193                     if (rp != null) {
4194                         return rp.GetExtendedDefaultProperty(_instance);
4195                     }
4196
4197                     ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4198                     if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4199                     return desc.GetDefaultProperty();
4200                 }
4201
4202                 /// <devdoc>
4203                 ///     ICustomTypeDescriptor implementation.
4204                 /// </devdoc>
4205                 object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
4206                 {
4207                     if (editorBaseType == null)
4208                     {
4209                         throw new ArgumentNullException("editorBaseType");
4210                     }
4211
4212                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4213                     // If so, we can call on it directly rather than creating another
4214                     // custom type descriptor
4215
4216                     TypeDescriptionProvider p = _node.Provider;
4217                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4218
4219                     if (rp != null) {
4220                         return rp.GetExtendedEditor(_instance, editorBaseType);
4221                     }
4222
4223                     ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4224                     if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4225                     return desc.GetEditor(editorBaseType);
4226                 }
4227
4228                 /// <devdoc>
4229                 ///     ICustomTypeDescriptor implementation.
4230                 /// </devdoc>
4231                 EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
4232                 {
4233                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4234                     // If so, we can call on it directly rather than creating another
4235                     // custom type descriptor
4236
4237                     TypeDescriptionProvider p = _node.Provider;
4238                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4239
4240                     if (rp != null) {
4241                         return rp.GetExtendedEvents(_instance);
4242                     }
4243
4244                     ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4245                     if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4246                     EventDescriptorCollection events = desc.GetEvents();
4247                     if (events == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetEvents"));
4248                     return events;
4249                 }
4250
4251                 /// <devdoc>
4252                 ///     ICustomTypeDescriptor implementation.
4253                 /// </devdoc>
4254                 EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
4255                 {
4256                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4257                     // If so, we can call on it directly rather than creating another
4258                     // custom type descriptor
4259
4260                     TypeDescriptionProvider p = _node.Provider;
4261                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4262
4263                     if (rp != null) {
4264                         // There is no need to filter these events.  For extended objects, they
4265                         // are accessed through our pipeline code, which always filters before
4266                         // returning.  So any filter we do here is redundant.  Note that we do
4267                         // pass a valid filter to a custom descriptor so it can optimize if it wants.
4268                         EventDescriptorCollection events = rp.GetExtendedEvents(_instance);
4269                         return events;
4270                     }
4271
4272                     ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4273                     if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4274                     EventDescriptorCollection evts = desc.GetEvents(attributes);
4275                     if (evts == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetEvents"));
4276                     return evts;
4277                 }
4278
4279                 /// <devdoc>
4280                 ///     ICustomTypeDescriptor implementation.
4281                 /// </devdoc>
4282                 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
4283                 {
4284                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4285                     // If so, we can call on it directly rather than creating another
4286                     // custom type descriptor
4287
4288                     TypeDescriptionProvider p = _node.Provider;
4289                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4290
4291                     if (rp != null) {
4292                         return rp.GetExtendedProperties(_instance);
4293                     }
4294
4295                     ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4296                     if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4297                     PropertyDescriptorCollection properties = desc.GetProperties();
4298                     if (properties == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetProperties"));
4299                     return properties;
4300                 }
4301
4302                 /// <devdoc>
4303                 ///     ICustomTypeDescriptor implementation.
4304                 /// </devdoc>
4305                 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
4306                 {
4307                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4308                     // If so, we can call on it directly rather than creating another
4309                     // custom type descriptor
4310
4311                     TypeDescriptionProvider p = _node.Provider;
4312                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4313
4314                     if (rp != null) {
4315                         // There is no need to filter these properties.  For extended objects, they
4316                         // are accessed through our pipeline code, which always filters before
4317                         // returning.  So any filter we do here is redundant.  Note that we do
4318                         // pass a valid filter to a custom descriptor so it can optimize if it wants.
4319                         PropertyDescriptorCollection props = rp.GetExtendedProperties(_instance);
4320                         return props;
4321                     }
4322
4323                     ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4324                     if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4325                     PropertyDescriptorCollection properties = desc.GetProperties(attributes);
4326                     if (properties == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetProperties"));
4327                     return properties;
4328                 }
4329
4330                 /// <devdoc>
4331                 ///     ICustomTypeDescriptor implementation.
4332                 /// </devdoc>
4333                 object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
4334                 {
4335                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4336                     // If so, we can call on it directly rather than creating another
4337                     // custom type descriptor
4338
4339                     TypeDescriptionProvider p = _node.Provider;
4340                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4341
4342                     if (rp != null) {
4343                         return rp.GetExtendedPropertyOwner(_instance, pd);
4344                     }
4345
4346                     ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4347                     if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4348                     object owner = desc.GetPropertyOwner(pd);
4349                     if (owner == null) owner = _instance;
4350                     return owner;
4351                 }
4352             }
4353
4354             /// <devdoc>
4355             ///     The default type descriptor.
4356             /// </devdoc>
4357             private struct DefaultTypeDescriptor : ICustomTypeDescriptor
4358             {
4359                 private TypeDescriptionNode _node;
4360                 private Type                _objectType;
4361                 private object              _instance;
4362
4363                 /// <devdoc>
4364                 ///     Creates a new WalkingTypeDescriptor.
4365                 /// </devdoc>
4366                 internal DefaultTypeDescriptor(TypeDescriptionNode node, Type objectType, object instance)
4367                 {
4368                     _node = node;
4369                     _objectType = objectType;
4370                     _instance = instance;
4371                 }
4372
4373                 /// <devdoc>
4374                 ///     ICustomTypeDescriptor implementation.
4375                 /// </devdoc>
4376                 AttributeCollection ICustomTypeDescriptor.GetAttributes()
4377                 {
4378                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4379                     // If so, we can call on it directly rather than creating another
4380                     // custom type descriptor
4381
4382                     TypeDescriptionProvider p = _node.Provider;
4383                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4384                     AttributeCollection attrs;
4385
4386                     if (rp != null) {
4387                         attrs = rp.GetAttributes(_objectType);
4388                     }
4389                     else {
4390                         ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4391                         if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4392                         attrs = desc.GetAttributes();
4393                         if (attrs == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetAttributes"));
4394                     }
4395
4396                     return attrs;
4397                 }
4398
4399                 /// <devdoc>
4400                 ///     ICustomTypeDescriptor implementation.
4401                 /// </devdoc>
4402                 string ICustomTypeDescriptor.GetClassName()
4403                 {
4404                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4405                     // If so, we can call on it directly rather than creating another
4406                     // custom type descriptor
4407
4408                     TypeDescriptionProvider p = _node.Provider;
4409                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4410                     string name;
4411
4412                     if (rp != null) {
4413                         name = rp.GetClassName(_objectType);
4414                     }
4415                     else {
4416                         ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4417                         if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4418                         name = desc.GetClassName();
4419                         if (name == null) name = _objectType.FullName;
4420                     }
4421
4422                     return name;
4423                 }
4424
4425                 /// <devdoc>
4426                 ///     ICustomTypeDescriptor implementation.
4427                 /// </devdoc>
4428                 string ICustomTypeDescriptor.GetComponentName()
4429                 {
4430                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4431                     // If so, we can call on it directly rather than creating another
4432                     // custom type descriptor
4433
4434                     TypeDescriptionProvider p = _node.Provider;
4435                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4436                     string name;
4437
4438                     if (rp != null) {
4439                         name = rp.GetComponentName(_objectType, _instance);
4440                     }
4441                     else {
4442                         ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4443                         if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4444                         name = desc.GetComponentName();
4445                     }
4446
4447                     return name;
4448                 }
4449
4450                 /// <devdoc>
4451                 ///     ICustomTypeDescriptor implementation.
4452                 /// </devdoc>
4453                 TypeConverter ICustomTypeDescriptor.GetConverter()
4454                 {
4455                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4456                     // If so, we can call on it directly rather than creating another
4457                     // custom type descriptor
4458
4459                     TypeDescriptionProvider p = _node.Provider;
4460                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4461                     TypeConverter converter;
4462
4463                     if (rp != null) {
4464                         converter = rp.GetConverter(_objectType, _instance);
4465                     }
4466                     else {
4467                         ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4468                         if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4469                         converter = desc.GetConverter();
4470                         if (converter == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetConverter"));
4471                     }
4472                         
4473                     return converter;
4474                 }
4475
4476                 /// <devdoc>
4477                 ///     ICustomTypeDescriptor implementation.
4478                 /// </devdoc>
4479                 EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
4480                 {
4481                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4482                     // If so, we can call on it directly rather than creating another
4483                     // custom type descriptor
4484
4485                     TypeDescriptionProvider p = _node.Provider;
4486                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4487                     EventDescriptor defaultEvent;
4488
4489                     if (rp != null) {
4490                         defaultEvent = rp.GetDefaultEvent(_objectType, _instance);
4491                     }
4492                     else {
4493                         ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4494                         if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4495                         defaultEvent = desc.GetDefaultEvent();
4496                     }
4497
4498                     return defaultEvent;
4499                 }
4500
4501                 /// <devdoc>
4502                 ///     ICustomTypeDescriptor implementation.
4503                 /// </devdoc>
4504                 PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
4505                 {
4506                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4507                     // If so, we can call on it directly rather than creating another
4508                     // custom type descriptor
4509
4510                     TypeDescriptionProvider p = _node.Provider;
4511                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4512                     PropertyDescriptor defaultProperty;
4513
4514                     if (rp != null) {
4515                         defaultProperty = rp.GetDefaultProperty(_objectType, _instance);
4516                     }
4517                     else {
4518                         ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4519                         if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4520                         defaultProperty = desc.GetDefaultProperty();
4521                     }
4522
4523                     return defaultProperty;
4524                 }
4525
4526                 /// <devdoc>
4527                 ///     ICustomTypeDescriptor implementation.
4528                 /// </devdoc>
4529                 object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
4530                 {
4531                     if (editorBaseType == null)
4532                     {
4533                         throw new ArgumentNullException("editorBaseType");
4534                     }
4535
4536                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4537                     // If so, we can call on it directly rather than creating another
4538                     // custom type descriptor
4539
4540                     TypeDescriptionProvider p = _node.Provider;
4541                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4542                     object editor;
4543
4544                     if (rp != null) {
4545                         editor = rp.GetEditor(_objectType, _instance, editorBaseType);
4546                     }
4547                     else {
4548                         ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4549                         if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4550                         editor = desc.GetEditor(editorBaseType);
4551                     }
4552
4553                     return editor;
4554                 }
4555
4556                 /// <devdoc>
4557                 ///     ICustomTypeDescriptor implementation.
4558                 /// </devdoc>
4559                 EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
4560                 {
4561                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4562                     // If so, we can call on it directly rather than creating another
4563                     // custom type descriptor
4564
4565                     TypeDescriptionProvider p = _node.Provider;
4566                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4567                     EventDescriptorCollection events;
4568
4569                     if (rp != null) {
4570                         events = rp.GetEvents(_objectType);
4571                     }
4572                     else {
4573                         ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4574                         if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4575                         events = desc.GetEvents();
4576                         if (events == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetEvents"));
4577                     }
4578
4579                     return events;
4580                 }
4581
4582                 /// <devdoc>
4583                 ///     ICustomTypeDescriptor implementation.
4584                 /// </devdoc>
4585                 EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
4586                 {
4587                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4588                     // If so, we can call on it directly rather than creating another
4589                     // custom type descriptor
4590
4591                     TypeDescriptionProvider p = _node.Provider;
4592                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4593                     EventDescriptorCollection events;
4594
4595                     if (rp != null) {
4596                         events = rp.GetEvents(_objectType);
4597                     }
4598                     else {
4599                         ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4600                         if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4601                         events = desc.GetEvents(attributes);
4602                         if (events == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetEvents"));
4603                     } 
4604
4605                     return events;
4606                 }
4607
4608                 /// <devdoc>
4609                 ///     ICustomTypeDescriptor implementation.
4610                 /// </devdoc>
4611                 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
4612                 {
4613                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4614                     // If so, we can call on it directly rather than creating another
4615                     // custom type descriptor
4616
4617                     TypeDescriptionProvider p = _node.Provider;
4618                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4619                     PropertyDescriptorCollection properties;
4620
4621                     if (rp != null) {
4622                         properties = rp.GetProperties(_objectType);
4623                     }
4624                     else {
4625                         ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4626                         if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4627                         properties = desc.GetProperties();
4628                         if (properties == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetProperties"));
4629                     }
4630
4631                     return properties;
4632                 }
4633
4634                 /// <devdoc>
4635                 ///     ICustomTypeDescriptor implementation.
4636                 /// </devdoc>
4637                 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
4638                 {
4639                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4640                     // If so, we can call on it directly rather than creating another
4641                     // custom type descriptor
4642
4643                     TypeDescriptionProvider p = _node.Provider;
4644                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4645                     PropertyDescriptorCollection properties;
4646
4647                     if (rp != null) {
4648                         properties = rp.GetProperties(_objectType);
4649                     }
4650                     else {
4651                         ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4652                         if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4653                         properties = desc.GetProperties(attributes);
4654                         if (properties == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetProperties"));
4655                     }
4656
4657                     return properties;
4658                 }
4659
4660                 /// <devdoc>
4661                 ///     ICustomTypeDescriptor implementation.
4662                 /// </devdoc>
4663                 object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
4664                 {
4665                     // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4666                     // If so, we can call on it directly rather than creating another
4667                     // custom type descriptor
4668
4669                     TypeDescriptionProvider p = _node.Provider;
4670                     ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4671                     object owner;
4672
4673                     if (rp != null) {
4674                         owner = rp.GetPropertyOwner(_objectType, _instance, pd);
4675                     }
4676                     else {
4677                         ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4678                         if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4679                         owner = desc.GetPropertyOwner(pd);
4680                         if (owner == null) owner = _instance;
4681                     }
4682
4683                     return owner;
4684                 }
4685             }
4686         }
4687
4688         /// <devdoc>
4689         ///     This is a simple internal type that allows external parties
4690         ///     to public ina custom type description provider for COM
4691         ///     objects.
4692         /// </devdoc>
4693         [TypeDescriptionProvider("System.Windows.Forms.ComponentModel.Com2Interop.ComNativeDescriptor, " + AssemblyRef.SystemWindowsForms)]
4694         private sealed class TypeDescriptorComObject
4695         {
4696         }
4697
4698         /// <devdoc>
4699         ///     This is a simple internal type that allows external parties to
4700         ///     register a custom type description provider for all interface types.
4701         /// </devdoc>
4702         private sealed class TypeDescriptorInterface
4703         {
4704         }
4705     }
4706 }
4707