Disable CAS calls on System.Componentmodel.TypeDescriptor
[mono-project.git] / mcs / class / referencesource / System / compmod / system / componentmodel / TypeDescriptor.cs
blobc1e1c43b23199a3ba9b9cfc98f580dd81d3699bc
1 //------------------------------------------------------------------------------
2 // <copyright file="TypeDescriptor.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
7 /*
8 */
9 namespace System.ComponentModel
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;
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
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.
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;
55 private static BooleanSwitch TraceDescriptor = new BooleanSwitch("TypeDescriptor", "Debug TypeDescriptor.");
57 #if DEBUG
58 private static BooleanSwitch EnableValidation = new BooleanSwitch("EnableValidation", "Enable type descriptor Whidbey->RTM validation");
59 #endif
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;
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[]
73 Guid.NewGuid(), // attributes
74 Guid.NewGuid(), // properties
75 Guid.NewGuid() // events
78 private static readonly Guid[] _pipelineMergeKeys = new Guid[]
80 Guid.NewGuid(), // attributes
81 Guid.NewGuid(), // properties
82 Guid.NewGuid() // events
85 private static readonly Guid[] _pipelineFilterKeys = new Guid[]
87 Guid.NewGuid(), // attributes
88 Guid.NewGuid(), // properties
89 Guid.NewGuid() // events
92 private static readonly Guid[] _pipelineAttributeFilterKeys = new Guid[]
94 Guid.NewGuid(), // attributes
95 Guid.NewGuid(), // properties
96 Guid.NewGuid() // events
99 private static object _internalSyncObject = new object();
101 private TypeDescriptor()
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
111 [PermissionSetAttribute(SecurityAction.LinkDemand, Name="FullTrust")]
112 get
114 TypeDescriptionNode node = NodeFor(ComObjectType);
115 ComNativeDescriptionProvider provider = null;
119 provider = node.Provider as ComNativeDescriptionProvider;
120 node = node.Next;
122 while(node != null && provider == null);
124 if (provider != null)
126 return provider.Handler;
129 return null;
131 [PermissionSetAttribute(SecurityAction.LinkDemand, Name="FullTrust")]
132 set
134 TypeDescriptionNode node = NodeFor(ComObjectType);
136 while (node != null && !(node.Provider is ComNativeDescriptionProvider))
138 node = node.Next;
141 if (node == null)
143 AddProvider(new ComNativeDescriptionProvider(value), ComObjectType);
145 else
147 ComNativeDescriptionProvider provider = (ComNativeDescriptionProvider)node.Provider;
148 provider.Handler = value;
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
163 return typeof(TypeDescriptorComObject);
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
176 return typeof(TypeDescriptorInterface);
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;
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;
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) {
209 if (type == null) {
210 throw new ArgumentNullException("type");
213 if (attributes == null) {
214 throw new ArgumentNullException("attributes");
217 TypeDescriptionProvider existingProvider = GetProvider(type);
218 TypeDescriptionProvider provider = new AttributeProvider(existingProvider, attributes);
219 TypeDescriptor.AddProvider(provider, type);
220 return provider;
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) {
237 if (instance == null) {
238 throw new ArgumentNullException("instance");
241 if (attributes == null) {
242 throw new ArgumentNullException("attributes");
245 TypeDescriptionProvider existingProvider = GetProvider(instance);
246 TypeDescriptionProvider provider = new AttributeProvider(existingProvider, attributes);
247 TypeDescriptor.AddProvider(provider, instance);
248 return provider;
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)
262 ReflectTypeDescriptionProvider.AddEditorTable(editorBaseType, table);
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)
278 if (provider == null)
280 throw new ArgumentNullException("provider");
283 if (type == null)
285 throw new ArgumentNullException("type");
288 lock(_providerTable)
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();
299 Refresh(type);
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)
313 if (provider == null)
315 throw new ArgumentNullException("provider");
318 if (instance == null)
320 throw new ArgumentNullException("instance");
322 bool refreshNeeded;
324 // Get the root node, hook it up, and stuff it back into
325 // the provider cache.
326 lock(_providerTable)
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();
336 if (refreshNeeded)
338 Refresh(instance, false);
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)
359 if (provider == null)
361 throw new ArgumentNullException("provider");
364 if (type == null)
366 throw new ArgumentNullException("type");
368 #if !DISABLE_CAS_USE
369 PermissionSet typeDescriptorPermission = new PermissionSet(PermissionState.None);
370 typeDescriptorPermission.AddPermission(new TypeDescriptorPermission(TypeDescriptorPermissionFlags.RestrictedRegistrationAccess));
372 PermissionSet targetPermissions = type.Assembly.PermissionSet;
373 targetPermissions = targetPermissions.Union(typeDescriptorPermission);
375 targetPermissions.Demand();
376 #endif
377 AddProvider(provider, type);
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)
395 if (provider == null)
397 throw new ArgumentNullException("provider");
400 if (instance == null)
402 throw new ArgumentNullException("instance");
404 #if !DISABLE_CAS_USE
405 Type type = instance.GetType();
407 PermissionSet typeDescriptorPermission = new PermissionSet(PermissionState.None);
408 typeDescriptorPermission.AddPermission(new TypeDescriptorPermission(TypeDescriptorPermissionFlags.RestrictedRegistrationAccess));
410 PermissionSet targetPermissions = type.Assembly.PermissionSet;
411 targetPermissions = targetPermissions.Union(typeDescriptorPermission);
413 targetPermissions.Demand();
414 #endif
415 AddProvider(provider, instance);
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)
427 if (_defaultProviders == null)
429 lock (_internalSyncObject)
431 if (_defaultProviders == null)
433 _defaultProviders = new Hashtable();
438 if (_defaultProviders.ContainsKey(type))
440 return;
443 lock (_internalSyncObject)
445 if (_defaultProviders.ContainsKey(type))
447 return;
450 // Immediately clear this. If we find a default provider
451 // and it starts messing around with type information,
452 // this could infinitely recurse.
454 _defaultProviders[type] = null;
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.
464 object[] attrs = type.GetCustomAttributes(typeof(TypeDescriptionProviderAttribute), false);
465 bool providerAdded = false;
466 for (int idx = attrs.Length - 1; idx >= 0; idx--)
468 TypeDescriptionProviderAttribute pa = (TypeDescriptionProviderAttribute)attrs[idx];
469 Type providerType = Type.GetType(pa.TypeName);
470 if (providerType != null && typeof(TypeDescriptionProvider).IsAssignableFrom(providerType))
472 TypeDescriptionProvider prov;
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 !DISABLE_CAS_USE
479 IntSecurity.FullReflection.Assert();
480 try {
481 #endif
482 prov = (TypeDescriptionProvider)Activator.CreateInstance(providerType);
483 #if !DISABLE_CAS_USE
485 finally {
486 CodeAccessPermission.RevertAssert();
488 #endif
489 Trace("Providers : Default provider found : {0}", providerType.Name);
490 AddProvider(prov, type);
491 providerAdded = true;
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);
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)
516 if (primary == null)
518 throw new ArgumentNullException("primary");
521 if (secondary == null)
523 throw new ArgumentNullException("secondary");
526 if (primary == secondary)
528 throw new ArgumentException(SR.GetString(SR.TypeDescriptorSameAssociation));
531 if (_associationTable == null)
533 lock (_internalSyncObject)
535 if (_associationTable == null)
537 _associationTable = new WeakHashtable();
542 IList associations = (IList)_associationTable[primary];
544 if (associations == null)
546 lock (_associationTable)
548 associations = (IList)_associationTable[primary];
549 if (associations == null)
551 associations = new ArrayList(4);
552 _associationTable.SetWeak(primary, associations);
556 else
558 for (int idx = associations.Count - 1; idx >= 0; idx--)
560 WeakReference r = (WeakReference)associations[idx];
561 if (r.IsAlive && r.Target == secondary)
563 throw new ArgumentException(SR.GetString(SR.TypeDescriptorAlreadyAssociated));
568 lock(associations)
570 associations.Add(new WeakReference(secondary));
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)
581 Type designerType = null;
582 IDesigner designer = null;
584 // Get the set of attributes for this type
586 AttributeCollection attributes = GetAttributes(component);
588 for (int i = 0; i < attributes.Count; i++)
590 DesignerAttribute da = attributes[i] as DesignerAttribute;
591 if (da != null)
593 Type attributeBaseType = Type.GetType(da.DesignerBaseTypeName);
594 if (attributeBaseType != null && attributeBaseType == designerBaseType)
596 ISite site = component.Site;
597 bool foundService = false;
599 if (site != null)
601 ITypeResolutionService tr = (ITypeResolutionService)site.GetService(typeof(ITypeResolutionService));
602 if (tr != null)
604 foundService = true;
605 designerType = tr.GetType(da.DesignerTypeName);
609 if (!foundService)
611 designerType = Type.GetType(da.DesignerTypeName);
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)
617 break;
623 if (designerType != null)
625 designer = (IDesigner)SecurityUtils.SecureCreateInstance(designerType, null, true);
628 return designer;
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)
637 return new ReflectEventDescriptor(componentType, name, type, attributes);
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)
647 return new ReflectEventDescriptor(componentType, oldEventDescriptor, attributes);
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)
657 if (objectType == null)
659 throw new ArgumentNullException("objectType");
662 if (argTypes != null)
664 if (args == null)
666 throw new ArgumentNullException("args");
669 if (argTypes.Length != args.Length)
671 throw new ArgumentException(SR.GetString(SR.TypeDescriptorArgsCountMismatch));
675 object instance = null;
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);
686 if (instance == null) {
687 instance = NodeFor(objectType).CreateInstance(provider, objectType, argTypes, args);
690 return instance;
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)
699 return new ReflectPropertyDescriptor(componentType, name, type, attributes);
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)
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.
717 if (componentType == oldPropertyDescriptor.ComponentType)
719 ExtenderProvidedPropertyAttribute attr = (ExtenderProvidedPropertyAttribute)
720 oldPropertyDescriptor.Attributes[
721 typeof(ExtenderProvidedPropertyAttribute)];
723 ReflectPropertyDescriptor reflectDesc = attr.ExtenderProperty as ReflectPropertyDescriptor;
724 if (reflectDesc != null)
726 return new ExtendedPropertyDescriptor(oldPropertyDescriptor, attributes);
728 #if DEBUG
729 else
731 DebugReflectPropertyDescriptor debugReflectDesc = attr.ExtenderProperty as DebugReflectPropertyDescriptor;
732 if (debugReflectDesc != null)
734 return new DebugExtendedPropertyDescriptor(oldPropertyDescriptor, attributes);
737 #endif
740 // This is either a normal prop or the caller has changed target classes.
742 return new ReflectPropertyDescriptor(componentType, oldPropertyDescriptor, attributes);
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)
754 // Check our switch first.
756 if (EnableValidation.Enabled)
758 while(key != null)
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))
765 return false;
768 if (key is Type)
770 key = GetNodeForBaseType((Type)key);
772 else
774 key = key.GetType();
775 if (((Type)key).IsCOMObject)
777 key = ComObjectType;
781 return true;
783 return false;
785 #endif
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)
795 #if DEBUG
796 if (!DebugShouldValidate(type)) return;
797 DebugValidate(attributes, debugAttributes);
798 #endif
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)
809 #if DEBUG
811 if (attributes.Count >= debugAttributes.Count)
813 foreach(Attribute a in attributes)
815 if (!(a is GuidAttribute) && !(a is ComVisibleAttribute))
817 bool found = false;
818 bool typeFound = false;
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"))
827 found = true;
828 break;
831 if (!found)
833 foreach(Attribute b in debugAttributes)
835 if (!typeFound && a.GetType() == b.GetType())
837 typeFound = true;
840 // Semitrust may throw here.
843 if (a.Equals(b))
845 found = true;
846 break;
849 catch
851 found = true;
852 break;
857 if (!found && !a.IsDefaultAttribute())
859 if (typeFound)
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));
863 else
865 Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Attribute {0} should not exist", a.GetType().Name));
871 else
873 foreach(Attribute b in debugAttributes)
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))
878 bool found = false;
879 bool typeFound = false;
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"))
888 found = true;
889 break;
892 if (!found)
894 foreach(Attribute a in attributes)
896 if (!typeFound && a.GetType() == b.GetType())
898 typeFound = true;
901 // Semitrust may throw here.
904 if (b.Equals(a))
906 found = true;
907 break;
910 catch
912 found = true;
913 break;
918 if (!found && !b.IsDefaultAttribute())
920 if (!typeFound)
922 Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Attribute {0} should exist", b.GetType().Name));
928 #endif
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)
939 #if DEBUG
940 if (!DebugShouldValidate(type)) return;
941 AttributeCollection debugAttributes = DebugTypeDescriptor.GetAttributes(type);
942 DebugValidate(attributes, debugAttributes);
943 #endif
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)
954 #if DEBUG
955 if (!DebugShouldValidate(instance)) return;
956 AttributeCollection debugAttributes = DebugTypeDescriptor.GetAttributes(instance, noCustomTypeDesc);
957 DebugValidate(attributes, debugAttributes);
958 #endif
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)
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
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)
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
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)
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)
1005 EventDescriptor evt = null;
1007 foreach(EventDescriptor realEvt in events)
1009 if (realEvt.Name.Equals(debugEvt.Name) && realEvt.EventType == debugEvt.EventType && realEvt.ComponentType == debugEvt.ComponentType)
1011 evt = realEvt;
1012 break;
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)
1019 AttributeCollection attrs = evt.Attributes;
1020 if (attrs[typeof(AttributeProviderAttribute)] == null)
1022 AttributeCollection debugAttrs = debugEvt.Attributes;
1023 DebugValidate(evt.EventType, attrs, debugAttrs);
1027 #endif
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)
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)
1044 EventDescriptor evt = null;
1046 foreach(EventDescriptor realEvt in events)
1048 if (realEvt.Name.Equals(debugEvt.Name) && realEvt.EventType == debugEvt.EventType && realEvt.ComponentType == debugEvt.ComponentType)
1050 evt = realEvt;
1051 break;
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)
1058 AttributeCollection attrs = evt.Attributes;
1059 if (attrs[typeof(AttributeProviderAttribute)] == null)
1061 AttributeCollection debugAttrs = debugEvt.Attributes;
1062 DebugValidate(evt.EventType, attrs, debugAttrs);
1066 #endif
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)
1077 #if DEBUG
1078 if (!DebugShouldValidate(type)) return;
1079 PropertyDescriptorCollection debugProperties = DebugTypeDescriptor.GetProperties(type, attributes);
1081 if (debugProperties.Count > properties.Count)
1083 foreach(PropertyDescriptor debugProp in debugProperties)
1085 PropertyDescriptor prop = null;
1087 foreach(PropertyDescriptor realProp in properties)
1089 if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
1091 prop = realProp;
1092 break;
1096 if (prop == null)
1098 Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should exist.", debugProp.Name, debugProp.GetType().Name));
1102 else if (properties.Count > debugProperties.Count)
1104 foreach(PropertyDescriptor prop in properties)
1106 PropertyDescriptor debugProp = null;
1108 foreach(PropertyDescriptor realProp in debugProperties)
1110 if (realProp.Name.Equals(prop.Name) && realProp.PropertyType == prop.PropertyType && realProp.ComponentType == prop.ComponentType)
1112 debugProp = realProp;
1113 break;
1117 if (debugProp == null)
1119 Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should not exist.", prop.Name, prop.GetType().Name));
1123 else
1125 foreach(PropertyDescriptor debugProp in debugProperties)
1127 PropertyDescriptor prop = null;
1129 foreach(PropertyDescriptor realProp in properties)
1131 if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
1133 prop = realProp;
1134 break;
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)
1141 AttributeCollection attrs = prop.Attributes;
1142 if (attrs[typeof(AttributeProviderAttribute)] == null)
1144 AttributeCollection debugAttrs = debugProp.Attributes;
1145 DebugValidate(prop.PropertyType, attrs, debugAttrs);
1150 #endif
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)
1161 #if DEBUG
1162 if (!DebugShouldValidate(instance)) return;
1163 PropertyDescriptorCollection debugProperties = DebugTypeDescriptor.GetProperties(instance, attributes, noCustomTypeDesc);
1165 if (debugProperties.Count > properties.Count)
1167 foreach(PropertyDescriptor debugProp in debugProperties)
1169 PropertyDescriptor prop = null;
1171 foreach(PropertyDescriptor realProp in properties)
1173 if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
1175 prop = realProp;
1176 break;
1180 if (prop == null)
1182 Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should exist.", debugProp.Name, debugProp.GetType().Name));
1186 else if (properties.Count > debugProperties.Count)
1188 foreach(PropertyDescriptor prop in properties)
1190 PropertyDescriptor debugProp = null;
1192 foreach(PropertyDescriptor realProp in debugProperties)
1194 if (realProp.Name.Equals(prop.Name) && realProp.PropertyType == prop.PropertyType && realProp.ComponentType == prop.ComponentType)
1196 debugProp = realProp;
1197 break;
1201 if (debugProp == null)
1203 Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should not exist.", prop.Name, prop.GetType().Name));
1207 else
1209 foreach(PropertyDescriptor debugProp in debugProperties)
1211 PropertyDescriptor prop = null;
1213 foreach(PropertyDescriptor realProp in properties)
1215 if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
1217 prop = realProp;
1218 break;
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)
1225 AttributeCollection attrs = prop.Attributes;
1226 if (attrs[typeof(AttributeProviderAttribute)] == null)
1228 AttributeCollection debugAttrs = debugProp.Attributes;
1229 DebugValidate(prop.PropertyType, attrs, debugAttrs);
1234 #endif
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;
1248 for (int idx = 0; idx < memberCount; idx++) {
1250 bool hide = false;
1252 for (int attrIdx = 0; attrIdx < attributes.Length; attrIdx++) {
1253 if (ShouldHideMember((MemberDescriptor)members[idx], attributes[attrIdx])) {
1254 hide = true;
1255 break;
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]);
1270 else if (newMembers != null) {
1271 newMembers.Add(members[idx]);
1276 return newMembers;
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)
1286 if (type == null)
1288 throw new ArgumentNullException("type");
1291 if (primary == null)
1293 throw new ArgumentNullException("primary");
1296 object associatedObject = primary;
1298 if (!type.IsInstanceOfType(primary))
1300 // Check our association table for a match.
1302 Hashtable assocTable = _associationTable;
1303 if (assocTable != null)
1305 IList associations = (IList)assocTable[primary];
1306 if (associations != null)
1308 lock(associations)
1310 for (int idx = associations.Count - 1; idx >= 0; idx--)
1312 // Look for an associated object that has a type that
1313 // matches the given type.
1315 WeakReference weakRef = (WeakReference)associations[idx];
1316 object secondary = weakRef.Target;
1317 if (secondary == null)
1319 Trace("Associations : Removing dead reference in assocation table");
1320 associations.RemoveAt(idx);
1322 else if (type.IsInstanceOfType(secondary))
1324 Trace("Associations : Associated {0} to {1}", primary.GetType().Name, secondary.GetType().Name);
1325 associatedObject = secondary;
1332 // Not in our table. We have a default association with a designer
1333 // if that designer is a component.
1335 if (associatedObject == primary)
1337 IComponent component = primary as IComponent;
1338 if (component != null)
1340 ISite site = component.Site;
1342 if (site != null && site.DesignMode)
1344 IDesignerHost host = site.GetService(typeof(IDesignerHost)) as IDesignerHost;
1345 if (host != null)
1347 object designer = host.GetDesigner(component);
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.
1354 if (designer != null && type.IsInstanceOfType(designer))
1356 Trace("Associations : Associated {0} to {1}", primary.GetType().Name, designer.GetType().Name);
1357 associatedObject = designer;
1365 return associatedObject;
1368 /// <devdoc>
1369 /// Gets a collection of attributes for the specified type of component.
1370 /// </devdoc>
1371 public static AttributeCollection GetAttributes(Type componentType)
1373 if (componentType == null)
1375 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
1376 return new AttributeCollection((Attribute[])null);
1379 AttributeCollection attributes = GetDescriptor(componentType, "componentType").GetAttributes();
1380 DebugValidate(attributes, componentType);
1381 return attributes;
1384 /// <devdoc>
1385 /// Gets a collection of attributes for the specified component.
1386 /// </devdoc>
1387 public static AttributeCollection GetAttributes(object component)
1389 return GetAttributes(component, false);
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)
1398 if (component == null)
1400 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
1401 return new AttributeCollection((Attribute[])null);
1404 // We create a sort of pipeline for mucking with metadata. The pipeline
1405 // goes through the following process:
1407 // 1. Merge metadata from extenders.
1408 // 2. Allow services to filter the metadata
1409 // 3. If an attribute filter was specified, apply that.
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.
1422 ICustomTypeDescriptor typeDesc = GetDescriptor(component, noCustomTypeDesc);
1423 ICollection results = typeDesc.GetAttributes();
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.
1435 if (component is ICustomTypeDescriptor)
1437 if (noCustomTypeDesc)
1439 ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
1440 if (extDesc != null)
1442 ICollection extResults = extDesc.GetAttributes();
1443 results = PipelineMerge(PIPELINE_ATTRIBUTES, results, extResults, component, null);
1446 else
1448 results = PipelineFilter(PIPELINE_ATTRIBUTES, results, component, null);
1451 else
1453 IDictionary cache = GetCache(component);
1455 results = PipelineInitialize(PIPELINE_ATTRIBUTES, results, cache);
1457 ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
1458 if (extDesc != null)
1460 ICollection extResults = extDesc.GetAttributes();
1461 results = PipelineMerge(PIPELINE_ATTRIBUTES, results, extResults, component, cache);
1464 results = PipelineFilter(PIPELINE_ATTRIBUTES, results, component, cache);
1467 AttributeCollection attrs = results as AttributeCollection;
1468 if (attrs == null)
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);
1476 DebugValidate(attrs, component, noCustomTypeDesc);
1477 return attrs;
1480 /// <devdoc>
1481 /// Helper function to obtain a cache for the given object.
1482 /// </devdoc>
1483 internal static IDictionary GetCache(object instance)
1485 return NodeFor(instance).GetCache(instance);
1488 /// <devdoc>
1489 /// Gets the name of the class for the specified component.
1490 /// </devdoc>
1491 public static string GetClassName(object component)
1493 return GetClassName(component, false);
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)
1502 return GetDescriptor(component, noCustomTypeDesc).GetClassName();
1505 /// <devdoc>
1506 /// Gets the name of the class for the specified type.
1507 /// </devdoc>
1508 public static string GetClassName(Type componentType)
1510 return GetDescriptor(componentType, "componentType").GetClassName();
1513 /// <devdoc>
1514 /// The name of the class for the specified component.
1515 /// </devdoc>
1516 public static string GetComponentName(object component)
1518 return GetComponentName(component, false);
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)
1527 return GetDescriptor(component, noCustomTypeDesc).GetComponentName();
1530 /// <devdoc>
1531 /// Gets a type converter for the type of the specified component.
1532 /// </devdoc>
1533 public static TypeConverter GetConverter(object component)
1535 return GetConverter(component, false);
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)
1544 TypeConverter converter = GetDescriptor(component, noCustomTypeDesc).GetConverter();
1545 DebugValidate(converter, component, noCustomTypeDesc);
1546 return converter;
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)
1555 TypeConverter converter = GetDescriptor(type, "type").GetConverter();
1556 DebugValidate(converter, type);
1557 return converter;
1560 /// <devdoc>
1561 /// Gets the default event for the specified type of component.
1562 /// </devdoc>
1563 public static EventDescriptor GetDefaultEvent(Type componentType)
1565 if (componentType == null)
1567 Debug.Fail("COMPAT: Returning null, but you should not pass null here");
1568 return null;
1571 return GetDescriptor(componentType, "componentType").GetDefaultEvent();
1574 /// <devdoc>
1575 /// Gets the default event for the specified component.
1576 /// </devdoc>
1577 public static EventDescriptor GetDefaultEvent(object component)
1579 return GetDefaultEvent(component, false);
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)
1588 if (component == null)
1590 Debug.Fail("COMPAT: Returning null, but you should not pass null here");
1591 return null;
1594 return GetDescriptor(component, noCustomTypeDesc).GetDefaultEvent();
1597 /// <devdoc>
1598 /// Gets the default property for the specified type of component.
1599 /// </devdoc>
1600 public static PropertyDescriptor GetDefaultProperty(Type componentType)
1602 if (componentType == null)
1604 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
1605 return null;
1608 return GetDescriptor(componentType, "componentType").GetDefaultProperty();
1611 /// <devdoc>
1612 /// Gets the default property for the specified component.
1613 /// </devdoc>
1614 public static PropertyDescriptor GetDefaultProperty(object component)
1616 return GetDefaultProperty(component, false);
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)
1625 if (component == null)
1627 Debug.Fail("COMPAT: Returning null, but you should not pass null here");
1628 return null;
1631 return GetDescriptor(component, noCustomTypeDesc).GetDefaultProperty();
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)
1640 if (type == null)
1642 throw new ArgumentNullException(typeName);
1645 return NodeFor(type).GetTypeDescriptor(type);
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)
1656 if (component == null)
1658 throw new ArgumentException("component");
1661 if (component is IUnimplemented) {
1662 throw new NotSupportedException(SR.GetString(SR.TypeDescriptorUnsupportedRemoteObject, component.GetType().FullName));
1666 ICustomTypeDescriptor desc = NodeFor(component).GetTypeDescriptor(component);
1667 ICustomTypeDescriptor d = component as ICustomTypeDescriptor;
1668 if (!noCustomTypeDesc && d != null)
1670 desc = new MergedTypeDescriptor(d, desc);
1673 return desc;
1676 /// <devdoc>
1677 /// Returns an extended custom type descriptor for the given instance.
1678 /// </devdoc>
1679 internal static ICustomTypeDescriptor GetExtendedDescriptor(object component)
1681 if (component == null)
1683 throw new ArgumentException("component");
1686 return NodeFor(component).GetExtendedTypeDescriptor(component);
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)
1695 return GetEditor(component, editorBaseType, false);
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)
1705 if (editorBaseType == null)
1707 throw new ArgumentNullException("editorBaseType");
1710 return GetDescriptor(component, noCustomTypeDesc).GetEditor(editorBaseType);
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)
1718 if (editorBaseType == null)
1720 throw new ArgumentNullException("editorBaseType");
1723 return GetDescriptor(type, "type").GetEditor(editorBaseType);
1726 /// <devdoc>
1727 /// Gets a collection of events for a specified type of component.
1728 /// </devdoc>
1729 public static EventDescriptorCollection GetEvents(Type componentType)
1731 if (componentType == null)
1733 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
1734 return new EventDescriptorCollection(null, true);
1737 return GetDescriptor(componentType, "componentType").GetEvents();
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)
1746 if (componentType == null)
1748 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
1749 return new EventDescriptorCollection(null, true);
1752 EventDescriptorCollection events = GetDescriptor(componentType, "componentType").GetEvents(attributes);
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);
1761 DebugValidate(events, componentType, attributes);
1762 return events;
1765 /// <devdoc>
1766 /// Gets a collection of events for a specified component.
1767 /// </devdoc>
1768 public static EventDescriptorCollection GetEvents(object component)
1770 return GetEvents(component, null, false);
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)
1779 return GetEvents(component, null, noCustomTypeDesc);
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)
1788 return GetEvents(component, attributes, false);
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)
1798 if (component == null)
1800 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
1801 return new EventDescriptorCollection(null, true);
1804 // We create a sort of pipeline for mucking with metadata. The pipeline
1805 // goes through the following process:
1807 // 1. Merge metadata from extenders.
1808 // 2. Allow services to filter the metadata
1809 // 3. If an attribute filter was specified, apply that.
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.
1822 ICustomTypeDescriptor typeDesc = GetDescriptor(component, noCustomTypeDesc);
1823 ICollection results;
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.
1835 if (component is ICustomTypeDescriptor)
1837 results = typeDesc.GetEvents(attributes);
1838 if (noCustomTypeDesc)
1840 ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
1841 if (extDesc != null)
1843 ICollection extResults = extDesc.GetEvents(attributes);
1844 results = PipelineMerge(PIPELINE_EVENTS, results, extResults, component, null);
1847 else
1849 results = PipelineFilter(PIPELINE_EVENTS, results, component, null);
1850 results = PipelineAttributeFilter(PIPELINE_EVENTS, results, attributes, component, null);
1853 else
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)
1861 ICollection extResults = extDesc.GetEvents(attributes);
1862 results = PipelineMerge(PIPELINE_EVENTS, results, extResults, component, cache);
1865 results = PipelineFilter(PIPELINE_EVENTS, results, component, cache);
1866 results = PipelineAttributeFilter(PIPELINE_EVENTS, results, attributes, component, cache);
1869 EventDescriptorCollection evts = results as EventDescriptorCollection;
1870 if (evts == null)
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);
1878 DebugValidate(evts, component, attributes, noCustomTypeDesc);
1880 return evts;
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)
1893 string suffix = null;
1895 ExtenderProvidedPropertyAttribute exAttr = member.Attributes[typeof(ExtenderProvidedPropertyAttribute)] as ExtenderProvidedPropertyAttribute;
1896 if (exAttr != null)
1898 IExtenderProvider prov = exAttr.Provider;
1900 if (prov != null)
1902 string name = null;
1903 IComponent component = prov as IComponent;
1905 if (component != null && component.Site != null)
1907 name = component.Site.Name;
1910 if (name == null || name.Length == 0)
1912 int ci = System.Threading.Interlocked.Increment(ref _collisionIndex) - 1;
1913 name = ci.ToString(CultureInfo.InvariantCulture);
1916 suffix = string.Format(CultureInfo.InvariantCulture, "_{0}", name);
1920 return suffix;
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);
1934 private static Type GetNodeForBaseType(Type searchType)
1936 if (searchType.IsInterface)
1938 return InterfaceType;
1940 else if (searchType == InterfaceType)
1942 return null;
1944 return searchType.BaseType;
1947 /// <devdoc>
1948 /// Gets a collection of properties for a specified type of component.
1949 /// </devdoc>
1950 public static PropertyDescriptorCollection GetProperties(Type componentType)
1952 if (componentType == null)
1954 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
1955 return new PropertyDescriptorCollection(null, true);
1958 return GetDescriptor(componentType, "componentType").GetProperties();
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)
1967 if (componentType == null)
1969 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
1970 return new PropertyDescriptorCollection(null, true);
1973 PropertyDescriptorCollection properties = GetDescriptor(componentType, "componentType").GetProperties(attributes);
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);
1982 DebugValidate(properties, componentType, attributes);
1983 return properties;
1986 /// <devdoc>
1987 /// Gets a collection of properties for a specified component.
1988 /// </devdoc>
1989 public static PropertyDescriptorCollection GetProperties(object component)
1991 return GetProperties(component, false);
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)
2000 return GetPropertiesImpl(component, null, noCustomTypeDesc, true);
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)
2010 return GetProperties(component, attributes, false);
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);
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)
2030 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
2031 return new PropertyDescriptorCollection(null, true);
2034 // We create a sort of pipeline for mucking with metadata. The pipeline
2035 // goes through the following process:
2037 // 1. Merge metadata from extenders.
2038 // 2. Allow services to filter the metadata
2039 // 3. If an attribute filter was specified, apply that.
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.
2052 ICustomTypeDescriptor typeDesc = GetDescriptor(component, noCustomTypeDesc);
2053 ICollection results;
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.
2065 if (component is ICustomTypeDescriptor)
2067 results = noAttributes ? typeDesc.GetProperties() : typeDesc.GetProperties(attributes);
2068 if (noCustomTypeDesc)
2070 ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
2071 if (extDesc != null)
2073 ICollection extResults = noAttributes ? extDesc.GetProperties() : extDesc.GetProperties(attributes);
2074 results = PipelineMerge(PIPELINE_PROPERTIES, results, extResults, component, null);
2077 else
2079 results = PipelineFilter(PIPELINE_PROPERTIES, results, component, null);
2080 results = PipelineAttributeFilter(PIPELINE_PROPERTIES, results, attributes, component, null);
2083 else
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)
2091 ICollection extResults = noAttributes ? extDesc.GetProperties() : extDesc.GetProperties(attributes);
2092 results = PipelineMerge(PIPELINE_PROPERTIES, results, extResults, component, cache);
2095 results = PipelineFilter(PIPELINE_PROPERTIES, results, component, cache);
2096 results = PipelineAttributeFilter(PIPELINE_PROPERTIES, results, attributes, component, cache);
2099 PropertyDescriptorCollection props = results as PropertyDescriptorCollection;
2100 if (props == null)
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);
2108 DebugValidate(props, component, attributes, noCustomTypeDesc);
2110 return props;
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)
2123 if (type == null)
2125 throw new ArgumentNullException("type");
2128 return NodeFor(type, true);
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)
2141 if (instance == null)
2143 throw new ArgumentNullException("instance");
2146 return NodeFor(instance, true);
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);
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)
2166 if (type == null)
2168 throw new ArgumentNullException("type");
2171 return NodeFor(type).GetReflectionType(type);
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)
2180 if (instance == null)
2182 throw new ArgumentNullException("instance");
2185 return NodeFor(instance).GetReflectionType(instance);
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);
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.
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.
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);
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.
2224 TypeDescriptionNode node = null;
2225 Type searchType = type;
2227 while (node == null) {
2228 node = (TypeDescriptionNode)_providerTypeTable[searchType];
2229 if (node == null) {
2230 node = (TypeDescriptionNode)_providerTable[searchType];
2233 if (node == null) {
2234 Type baseType = GetNodeForBaseType(searchType);
2236 if (searchType == typeof(object) || baseType == null) {
2238 lock (_providerTable) {
2239 node = (TypeDescriptionNode)_providerTable[searchType];
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);
2251 else if (createDelegator) {
2252 node = new TypeDescriptionNode(new DelegatingTypeDescriptionProvider(baseType));
2253 lock (_providerTable) {
2254 _providerTypeTable[searchType] = node;
2257 else {
2258 // Continue our search
2259 searchType = baseType;
2264 return node;
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)
2275 return NodeFor(instance, false);
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)
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.
2301 Debug.Assert(instance != null, "Caller should validate");
2303 TypeDescriptionNode node = (TypeDescriptionNode)_providerTable[instance];
2304 if (node == null)
2306 Type type = instance.GetType();
2308 if (type.IsCOMObject)
2310 type = ComObjectType;
2313 if (createDelegator)
2315 node = new TypeDescriptionNode(new DelegatingTypeDescriptionProvider(type));
2316 Trace("Nodes : Allocated new instance node for {0}. Now {1} nodes", type.Name, _providerTable.Count);
2318 else
2320 node = NodeFor(type);
2324 return node;
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.
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)
2347 lock(_providerTable)
2349 TypeDescriptionNode head = (TypeDescriptionNode)_providerTable[key];
2350 TypeDescriptionNode target = head;
2351 TypeDescriptionNode prev = null;
2353 while(target != null && target.Provider != provider)
2355 prev = target;
2356 target = target.Next;
2359 if (target != null)
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.
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;
2374 // Now remove target.Next from the list
2375 target.Next = target.Next.Next;
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);
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.
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.
2398 Type keyType = key as Type;
2399 if (keyType == null) keyType = key.GetType();
2401 target.Provider = new DelegatingTypeDescriptionProvider(keyType.BaseType);
2403 else {
2404 _providerTable.Remove(key);
2407 // Finally, clear our cache of provider types; it might be invalid
2408 // now.
2409 _providerTypeTable.Clear();
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)
2420 Debug.Assert(pipelineType != PIPELINE_ATTRIBUTES, "PipelineAttributeFilter is not supported for attributes");
2422 IList list = members as ArrayList;
2424 if (filter == null || filter.Length == 0)
2426 return members;
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.
2434 if (cache != null && (list == null || list.IsReadOnly))
2436 AttributeFilterCacheItem filterCache = cache[_pipelineAttributeFilterKeys[pipelineType]] as AttributeFilterCacheItem;
2437 if (filterCache != null && filterCache.IsValid(filter))
2439 return filterCache.FilteredMembers;
2443 // Our cache did not contain the correct state, so generate it.
2445 if (list == null || list.IsReadOnly)
2447 Trace("Pipeline : Filter needs to create member list for {0}", instance.GetType().Name);
2448 list = new ArrayList(members);
2451 ArrayList filterResult = FilterMembers(list, filter);
2452 if (filterResult != null) list = filterResult;
2454 // And, if we have a cache, store the updated state into it for future reference.
2456 if (cache != null)
2458 ICollection cacheValue;
2460 switch(pipelineType)
2462 case PIPELINE_PROPERTIES:
2463 PropertyDescriptor[] propArray = new PropertyDescriptor[list.Count];
2464 list.CopyTo(propArray, 0);
2465 cacheValue = new PropertyDescriptorCollection(propArray, true);
2466 break;
2468 case PIPELINE_EVENTS:
2469 EventDescriptor[] eventArray = new EventDescriptor[list.Count];
2470 list.CopyTo(eventArray, 0);
2471 cacheValue = new EventDescriptorCollection(eventArray, true);
2472 break;
2474 default:
2475 Debug.Fail("unknown pipeline type");
2476 cacheValue = null;
2477 break;
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;
2485 return list;
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)
2498 IComponent component = instance as IComponent;
2499 ITypeDescriptorFilterService componentFilter = null;
2501 if (component != null)
2503 ISite site = component.Site;
2504 if (site != null)
2506 componentFilter = site.GetService(typeof(ITypeDescriptorFilterService)) as ITypeDescriptorFilterService;
2510 // If we have no filter, there is nothing for us to do.
2512 IList list = members as ArrayList;
2514 if (componentFilter == null)
2516 Debug.Assert(cache == null || list == null || !cache.Contains(_pipelineFilterKeys[pipelineType]), "Earlier pipeline stage should have removed our cache");
2517 return members;
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.
2525 if (cache != null && (list == null || list.IsReadOnly))
2527 FilterCacheItem cacheItem = cache[_pipelineFilterKeys[pipelineType]] as FilterCacheItem;
2528 if (cacheItem != null && cacheItem.IsValid(componentFilter)) {
2529 return cacheItem.FilteredMembers;
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.
2537 OrderedDictionary filterTable = new OrderedDictionary(members.Count);
2538 bool cacheResults;
2540 switch(pipelineType)
2542 case PIPELINE_ATTRIBUTES:
2543 foreach(Attribute attr in members)
2545 filterTable[attr.TypeId] = attr;
2547 cacheResults = componentFilter.FilterAttributes(component, filterTable);
2548 break;
2550 case PIPELINE_PROPERTIES:
2551 case PIPELINE_EVENTS:
2552 foreach(MemberDescriptor desc in members)
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.
2563 if (filterTable.Contains(descName))
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.
2573 string suffix = GetExtenderCollisionSuffix(desc);
2574 Debug.Assert(suffix != null, "Name collision with non-extender property.");
2575 if (suffix != null)
2577 filterTable[descName + suffix] = desc;
2580 // Now, handle the original property.
2582 MemberDescriptor origDesc = (MemberDescriptor)filterTable[descName];
2583 suffix = GetExtenderCollisionSuffix(origDesc);
2584 if (suffix != null)
2586 filterTable.Remove(descName);
2587 filterTable[origDesc.Name + suffix] = origDesc;
2590 else
2592 filterTable[descName] = desc;
2595 if (pipelineType == PIPELINE_PROPERTIES)
2597 cacheResults = componentFilter.FilterProperties(component, filterTable);
2599 else
2601 cacheResults = componentFilter.FilterEvents(component, filterTable);
2603 break;
2605 default:
2606 Debug.Fail("unknown pipeline type");
2607 cacheResults = false;
2608 break;
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.
2614 if (list == null || list.IsReadOnly)
2616 Trace("Pipeline : Filter needs to create member list for {0}", instance.GetType().Name);
2617 list = new ArrayList(filterTable.Values);
2619 else
2621 list.Clear();
2622 foreach(object obj in filterTable.Values)
2624 list.Add(obj);
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.
2634 if (cacheResults && cache != null)
2636 ICollection cacheValue;
2638 switch(pipelineType)
2640 case PIPELINE_ATTRIBUTES:
2641 Attribute[] attrArray = new Attribute[list.Count];
2644 list.CopyTo(attrArray, 0);
2646 catch(InvalidCastException)
2648 throw new ArgumentException(SR.GetString(SR.TypeDescriptorExpectedElementType, typeof(Attribute).FullName));
2650 cacheValue = new AttributeCollection(attrArray);
2651 break;
2653 case PIPELINE_PROPERTIES:
2654 PropertyDescriptor[] propArray = new PropertyDescriptor[list.Count];
2657 list.CopyTo(propArray, 0);
2659 catch(InvalidCastException)
2661 throw new ArgumentException(SR.GetString(SR.TypeDescriptorExpectedElementType, typeof(PropertyDescriptor).FullName));
2663 cacheValue = new PropertyDescriptorCollection(propArray, true);
2664 break;
2666 case PIPELINE_EVENTS:
2667 EventDescriptor[] eventArray = new EventDescriptor[list.Count];
2670 list.CopyTo(eventArray, 0);
2672 catch(InvalidCastException)
2674 throw new ArgumentException(SR.GetString(SR.TypeDescriptorExpectedElementType, typeof(EventDescriptor).FullName));
2676 cacheValue = new EventDescriptorCollection(eventArray, true);
2677 break;
2679 default:
2680 Debug.Fail("unknown pipeline type");
2681 cacheValue = null;
2682 break;
2685 Trace("Pipeline : Filter results being cached for {0}", instance.GetType().Name);
2687 FilterCacheItem cacheItem = new FilterCacheItem(componentFilter, cacheValue);
2688 cache[_pipelineFilterKeys[pipelineType]] = cacheItem;
2689 cache.Remove(_pipelineAttributeFilterKeys[pipelineType]);
2692 return list;
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) {
2702 bool cacheValid = true;
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();
2709 while(cacheEnum.MoveNext() && memberEnum.MoveNext()) {
2710 if (cacheEnum.Current != memberEnum.Current) {
2711 cacheValid = false;
2712 break;
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;
2727 return members;
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)
2737 // If there is no secondary collection, there is nothing to merge.
2739 if (secondary == null || secondary.Count == 0)
2741 return primary;
2744 // Next, if we were given a cache, see if it has accurate data.
2746 if (cache != null)
2748 ICollection mergeCache = cache[_pipelineMergeKeys[pipelineType]] as ICollection;
2749 if (mergeCache != null && mergeCache.Count == (primary.Count + secondary.Count))
2751 // Walk the merge cache.
2752 IEnumerator mergeEnum = mergeCache.GetEnumerator();
2753 IEnumerator primaryEnum = primary.GetEnumerator();
2754 bool match = true;
2756 while(primaryEnum.MoveNext() && mergeEnum.MoveNext())
2758 if (primaryEnum.Current != mergeEnum.Current)
2760 match = false;
2761 break;
2765 if (match)
2767 IEnumerator secondaryEnum = secondary.GetEnumerator();
2769 while(secondaryEnum.MoveNext() && mergeEnum.MoveNext())
2771 if (secondaryEnum.Current != mergeEnum.Current)
2773 match = false;
2774 break;
2779 if (match)
2781 return mergeCache;
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.
2791 ArrayList list = new ArrayList(primary.Count + secondary.Count);
2792 foreach(object obj in primary)
2794 list.Add(obj);
2796 foreach(object obj in secondary)
2798 list.Add(obj);
2801 if (cache != null)
2803 ICollection cacheValue;
2805 switch(pipelineType)
2807 case PIPELINE_ATTRIBUTES:
2808 Attribute[] attrArray = new Attribute[list.Count];
2809 list.CopyTo(attrArray, 0);
2810 cacheValue = new AttributeCollection(attrArray);
2811 break;
2813 case PIPELINE_PROPERTIES:
2814 PropertyDescriptor[] propArray = new PropertyDescriptor[list.Count];
2815 list.CopyTo(propArray, 0);
2816 cacheValue = new PropertyDescriptorCollection(propArray, true);
2817 break;
2819 case PIPELINE_EVENTS:
2820 EventDescriptor[] eventArray = new EventDescriptor[list.Count];
2821 list.CopyTo(eventArray, 0);
2822 cacheValue = new EventDescriptorCollection(eventArray, true);
2823 break;
2825 default:
2826 Debug.Fail("unknown pipeline type");
2827 cacheValue = null;
2828 break;
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]);
2837 return list;
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);
2846 if (handler != null)
2848 handler(new RefreshEventArgs(component));
2852 private static void RaiseRefresh(Type type) {
2853 RefreshEventHandler handler = Volatile.Read(ref Refreshed);
2855 if (handler != null)
2857 handler(new RefreshEventArgs(type));
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)
2867 Refresh(component, true);
2870 private static void Refresh(object component, bool refreshReflectionProvider) {
2871 #if DEBUG
2872 DebugTypeDescriptor.Refresh(component);
2873 #endif
2875 if (component == null)
2877 Debug.Fail("COMPAT: Returning, but you should not pass null here");
2878 return;
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;
2887 if (refreshReflectionProvider)
2889 Type type = component.GetType();
2891 lock (_providerTable)
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)
2898 Type nodeType = de.Key as Type;
2899 if (nodeType != null && type.IsAssignableFrom(nodeType) || nodeType == typeof(object))
2901 TypeDescriptionNode node = (TypeDescriptionNode)de.Value;
2902 while (node != null && !(node.Provider is ReflectTypeDescriptionProvider))
2904 found = true;
2905 node = node.Next;
2908 if (node != null)
2910 ReflectTypeDescriptionProvider provider = (ReflectTypeDescriptionProvider)node.Provider;
2911 if (provider.IsPopulated(type))
2913 found = true;
2914 provider.Refresh(type);
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).
2931 // Now, clear any cached data for the instance.
2933 IDictionary cache = GetCache(component);
2934 if (found || cache!= null)
2936 if (cache != null)
2938 Trace("Pipeline : Refresh clearing all pipeline caches");
2939 for (int idx = 0; idx < _pipelineFilterKeys.Length; idx++)
2941 cache.Remove(_pipelineFilterKeys[idx]);
2942 cache.Remove(_pipelineMergeKeys[idx]);
2943 cache.Remove(_pipelineAttributeFilterKeys[idx]);
2948 Interlocked.Increment(ref _metadataVersion);
2950 // And raise the event.
2952 RaiseRefresh(component);
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)
2962 #if DEBUG
2963 DebugTypeDescriptor.Refresh(type);
2964 #endif
2966 if (type == null)
2968 Debug.Fail("COMPAT: Returning, but you should not pass null here");
2969 return;
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.
2977 bool found = false;
2979 lock(_providerTable)
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)
2986 Type nodeType = de.Key as Type;
2987 if (nodeType != null && type.IsAssignableFrom(nodeType) || nodeType == typeof(object))
2989 TypeDescriptionNode node = (TypeDescriptionNode)de.Value;
2990 while(node != null && !(node.Provider is ReflectTypeDescriptionProvider))
2992 found = true;
2993 node = node.Next;
2996 if (node != null)
2998 ReflectTypeDescriptionProvider provider = (ReflectTypeDescriptionProvider)node.Provider;
2999 if (provider.IsPopulated(type))
3001 found = true;
3002 provider.Refresh(type);
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.
3014 if (found)
3016 Interlocked.Increment(ref _metadataVersion);
3018 // And raise the event.
3020 RaiseRefresh(type);
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)
3030 #if DEBUG
3031 DebugTypeDescriptor.Refresh(module);
3032 #endif
3034 if (module == null)
3036 Debug.Fail("COMPAT: Returning, but you should not pass null here");
3037 return;
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;
3046 lock(_providerTable)
3048 foreach(DictionaryEntry de in _providerTable)
3050 Type nodeType = de.Key as Type;
3051 if (nodeType != null && nodeType.Module.Equals(module) || nodeType == typeof(object))
3053 TypeDescriptionNode node = (TypeDescriptionNode)de.Value;
3054 while(node != null && !(node.Provider is ReflectTypeDescriptionProvider))
3056 if (refreshedTypes == null) {
3057 refreshedTypes = new Hashtable();
3059 refreshedTypes[nodeType] = nodeType;
3060 node = node.Next;
3063 if (node != null)
3065 ReflectTypeDescriptionProvider provider = (ReflectTypeDescriptionProvider)node.Provider;
3066 Type[] populatedTypes = provider.GetPopulatedTypes(module);
3068 foreach(Type populatedType in populatedTypes) {
3069 provider.Refresh(populatedType);
3070 if (refreshedTypes == null) {
3071 refreshedTypes = new Hashtable();
3073 refreshedTypes[populatedType] = populatedType;
3080 // And raise the event if types were refresh and handlers are attached.
3082 if (refreshedTypes != null && Refreshed != null)
3084 foreach(Type t in refreshedTypes.Keys) {
3085 RaiseRefresh(t);
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)
3098 if (assembly == null)
3100 Debug.Fail("COMPAT: Returning, but you should not pass null here");
3101 return;
3104 foreach (Module mod in assembly.GetModules())
3106 Refresh(mod);
3109 // Debug type descriptor has the same code, so our call above will handle this.
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)
3119 if (primary == null)
3121 throw new ArgumentNullException("primary");
3124 if (secondary == null)
3126 throw new ArgumentNullException("secondary");
3129 Hashtable assocTable = _associationTable;
3130 if (assocTable != null)
3132 IList associations = (IList)assocTable[primary];
3133 if (associations != null)
3135 lock(associations)
3137 for (int idx = associations.Count - 1; idx >= 0; idx--)
3139 // Look for an associated object that has a type that
3140 // matches the given type.
3142 WeakReference weakRef = (WeakReference)associations[idx];
3143 object secondaryItem = weakRef.Target;
3144 if (secondaryItem == null || secondaryItem == secondary)
3146 associations.RemoveAt(idx);
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)
3161 if (primary == null)
3163 throw new ArgumentNullException("primary");
3166 Hashtable assocTable = _associationTable;
3167 if (assocTable != null)
3169 assocTable.Remove(primary);
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)
3183 if (provider == null)
3185 throw new ArgumentNullException("provider");
3188 if (type == null)
3190 throw new ArgumentNullException("type");
3193 // Walk the nodes until we find the right one, and then remove it.
3194 NodeRemove(type, provider);
3195 RaiseRefresh(type);
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)
3208 if (provider == null)
3210 throw new ArgumentNullException("provider");
3213 if (instance == null)
3215 throw new ArgumentNullException("instance");
3218 // Walk the nodes until we find the right one, and then remove it.
3219 NodeRemove(instance, provider);
3220 RaiseRefresh(instance);
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)
3238 if (provider == null)
3240 throw new ArgumentNullException("provider");
3243 if (type == null)
3245 throw new ArgumentNullException("type");
3247 #if !DISABLE_CAS_USE
3248 PermissionSet typeDescriptorPermission = new PermissionSet(PermissionState.None);
3249 typeDescriptorPermission.AddPermission(new TypeDescriptorPermission(TypeDescriptorPermissionFlags.RestrictedRegistrationAccess));
3251 PermissionSet targetPermissions = type.Assembly.PermissionSet;
3252 targetPermissions = targetPermissions.Union(typeDescriptorPermission);
3254 targetPermissions.Demand();
3255 #endif
3256 RemoveProvider(provider, type);
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)
3273 if (provider == null)
3275 throw new ArgumentNullException("provider");
3278 if (instance == null)
3280 throw new ArgumentNullException("instance");
3282 #if !DISABLE_CAS_USE
3283 Type type = instance.GetType();
3285 PermissionSet typeDescriptorPermission = new PermissionSet(PermissionState.None);
3286 typeDescriptorPermission.AddPermission(new TypeDescriptorPermission(TypeDescriptorPermissionFlags.RestrictedRegistrationAccess));
3288 PermissionSet targetPermissions = type.Assembly.PermissionSet;
3289 targetPermissions = targetPermissions.Union(typeDescriptorPermission);
3291 targetPermissions.Demand();
3292 #endif
3293 RemoveProvider(provider, instance);
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)
3304 if (member == null || attribute == null)
3306 return true;
3309 Attribute memberAttribute = member.Attributes[attribute.GetType()];
3310 if (memberAttribute == null)
3312 return !attribute.IsDefaultAttribute();
3314 else
3316 return !(attribute.Match(memberAttribute));
3320 /// <devdoc>
3321 /// Sorts descriptors by name of the descriptor.
3322 /// </devdoc>
3323 public static void SortDescriptorArray(IList infos)
3325 if (infos == null)
3327 throw new ArgumentNullException("infos");
3330 ArrayList.Adapter(infos).Sort(MemberDescriptorComparer.Instance);
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)
3339 Debug.WriteLineIf(TraceDescriptor.Enabled, string.Format(CultureInfo.InvariantCulture, "TypeDescriptor : {0}", string.Format(CultureInfo.InvariantCulture, message, args)));
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
3349 Attribute[] _attrs;
3351 /// <devdoc>
3352 /// Creates a new attribute provider.
3353 /// </devdoc>
3354 internal AttributeProvider(TypeDescriptionProvider existingProvider, params Attribute[] attrs) : base(existingProvider)
3356 _attrs = attrs;
3359 /// <devdoc>
3360 /// Creates a custom type descriptor that replaces the attributes.
3361 /// </devdoc>
3362 public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
3364 return new AttributeTypeDescriptor(_attrs, base.GetTypeDescriptor(objectType, instance));
3367 /// <devdoc>
3368 /// Our custom type descriptor.
3369 /// </devdoc>
3370 private class AttributeTypeDescriptor : CustomTypeDescriptor
3372 Attribute[] _attributeArray;
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)
3380 _attributeArray = attrs;
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()
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);
3398 for (int idx = 0; idx < newAttrs.Length; idx++)
3401 Debug.Assert(newAttrs[idx] != null, "_attributes contains a null member");
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++)
3408 if (newArray[existingIdx].TypeId.Equals(newAttrs[idx].TypeId))
3410 match = true;
3411 newArray[existingIdx] = newAttrs[idx];
3412 break;
3416 if (!match)
3418 newArray[actualCount++] = newAttrs[idx];
3422 // Now, if we collapsed some attributes, create a new array.
3424 if (actualCount < newArray.Length)
3426 finalAttr = new Attribute[actualCount];
3427 Array.Copy(newArray, 0, finalAttr, 0, actualCount);
3429 else
3431 finalAttr= newArray;
3434 return new AttributeCollection(finalAttr);
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
3445 #pragma warning disable 618
3446 private IComNativeDescriptorHandler _handler;
3448 internal ComNativeDescriptionProvider(IComNativeDescriptorHandler handler)
3450 _handler = handler;
3453 /// <devdoc>
3454 /// Returns the COM handler object.
3455 /// </devdoc>
3456 internal IComNativeDescriptorHandler Handler
3460 return _handler;
3464 _handler = value;
3467 #pragma warning restore 618
3469 /// <devdoc>
3470 /// Implements GetTypeDescriptor. This creates a custom type
3471 /// descriptor that walks the linked list for each of its calls.
3472 /// </devdoc>
3474 [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters")]
3475 public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
3477 if (objectType == null)
3479 throw new ArgumentNullException("objectType");
3482 if (instance == null)
3484 return null;
3487 if (!objectType.IsInstanceOfType(instance))
3489 throw new ArgumentException("instance");
3492 return new ComNativeTypeDescriptor(_handler, instance);
3495 /// <devdoc>
3496 /// This type descriptor sits on top of a native
3497 /// descriptor handler.
3498 /// </devdoc>
3499 private sealed class ComNativeTypeDescriptor : ICustomTypeDescriptor
3501 #pragma warning disable 618
3502 private IComNativeDescriptorHandler _handler;
3503 private object _instance;
3505 /// <devdoc>
3506 /// Creates a new ComNativeTypeDescriptor.
3507 /// </devdoc>
3508 internal ComNativeTypeDescriptor(IComNativeDescriptorHandler handler, object instance)
3510 _handler = handler;
3511 _instance = instance;
3513 #pragma warning restore 618
3515 /// <devdoc>
3516 /// ICustomTypeDescriptor implementation.
3517 /// </devdoc>
3518 AttributeCollection ICustomTypeDescriptor.GetAttributes()
3520 return _handler.GetAttributes(_instance);
3523 /// <devdoc>
3524 /// ICustomTypeDescriptor implementation.
3525 /// </devdoc>
3526 string ICustomTypeDescriptor.GetClassName()
3528 return _handler.GetClassName(_instance);
3531 /// <devdoc>
3532 /// ICustomTypeDescriptor implementation.
3533 /// </devdoc>
3534 string ICustomTypeDescriptor.GetComponentName()
3536 return null;
3539 /// <devdoc>
3540 /// ICustomTypeDescriptor implementation.
3541 /// </devdoc>
3542 TypeConverter ICustomTypeDescriptor.GetConverter()
3544 return _handler.GetConverter(_instance);
3547 /// <devdoc>
3548 /// ICustomTypeDescriptor implementation.
3549 /// </devdoc>
3550 EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
3552 return _handler.GetDefaultEvent(_instance);
3555 /// <devdoc>
3556 /// ICustomTypeDescriptor implementation.
3557 /// </devdoc>
3558 PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
3560 return _handler.GetDefaultProperty(_instance);
3563 /// <devdoc>
3564 /// ICustomTypeDescriptor implementation.
3565 /// </devdoc>
3566 object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
3568 return _handler.GetEditor(_instance, editorBaseType);
3571 /// <devdoc>
3572 /// ICustomTypeDescriptor implementation.
3573 /// </devdoc>
3574 EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
3576 return _handler.GetEvents(_instance);
3579 /// <devdoc>
3580 /// ICustomTypeDescriptor implementation.
3581 /// </devdoc>
3582 EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
3584 return _handler.GetEvents(_instance, attributes);
3587 /// <devdoc>
3588 /// ICustomTypeDescriptor implementation.
3589 /// </devdoc>
3590 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
3592 return _handler.GetProperties(_instance, null);
3595 /// <devdoc>
3596 /// ICustomTypeDescriptor implementation.
3597 /// </devdoc>
3598 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
3600 return _handler.GetProperties(_instance, attributes);
3603 /// <devdoc>
3604 /// ICustomTypeDescriptor implementation.
3605 /// </devdoc>
3606 object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
3608 return _instance;
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
3620 private Attribute[] _filter;
3621 internal ICollection FilteredMembers;
3623 internal AttributeFilterCacheItem(Attribute[] filter, ICollection filteredMembers)
3625 _filter = filter;
3626 FilteredMembers = filteredMembers;
3629 internal bool IsValid(Attribute[] filter)
3631 if (_filter.Length != filter.Length) return false;
3633 for (int idx = 0; idx < filter.Length; idx++) {
3634 if (_filter[idx] != filter[idx]) {
3635 return false;
3639 return true;
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;
3651 internal FilterCacheItem(ITypeDescriptorFilterService filterService, ICollection filteredMembers) {
3652 _filterService = filterService;
3653 FilteredMembers = filteredMembers;
3656 internal bool IsValid(ITypeDescriptorFilterService filterService) {
3657 if (!Object.ReferenceEquals(_filterService, filterService)) return false;
3658 return true;
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.
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 {}
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();
3686 public int Compare(object left, object right) {
3687 return string.Compare(((MemberDescriptor)left).Name, ((MemberDescriptor)right).Name, false, CultureInfo.InvariantCulture);
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
3699 private ICustomTypeDescriptor _primary;
3700 private ICustomTypeDescriptor _secondary;
3702 /// <devdoc>
3703 /// Creates a new MergedTypeDescriptor.
3704 /// </devdoc>
3705 internal MergedTypeDescriptor(ICustomTypeDescriptor primary, ICustomTypeDescriptor secondary)
3707 _primary = primary;
3708 _secondary = secondary;
3711 /// <devdoc>
3712 /// ICustomTypeDescriptor implementation.
3713 /// </devdoc>
3714 AttributeCollection ICustomTypeDescriptor.GetAttributes()
3716 AttributeCollection attrs = _primary.GetAttributes();
3717 if (attrs == null)
3719 attrs = _secondary.GetAttributes();
3722 Debug.Assert(attrs != null, "Someone should have handled this");
3723 return attrs;
3726 /// <devdoc>
3727 /// ICustomTypeDescriptor implementation.
3728 /// </devdoc>
3729 string ICustomTypeDescriptor.GetClassName()
3731 string className = _primary.GetClassName();
3732 if (className == null)
3734 className = _secondary.GetClassName();
3737 Debug.Assert(className != null, "Someone should have handled this");
3738 return className;
3741 /// <devdoc>
3742 /// ICustomTypeDescriptor implementation.
3743 /// </devdoc>
3744 string ICustomTypeDescriptor.GetComponentName()
3746 string name = _primary.GetComponentName();
3747 if (name == null)
3749 name = _secondary.GetComponentName();
3752 return name;
3755 /// <devdoc>
3756 /// ICustomTypeDescriptor implementation.
3757 /// </devdoc>
3758 TypeConverter ICustomTypeDescriptor.GetConverter()
3760 TypeConverter converter = _primary.GetConverter();
3761 if (converter == null)
3763 converter = _secondary.GetConverter();
3766 Debug.Assert(converter != null, "Someone should have handled this");
3767 return converter;
3770 /// <devdoc>
3771 /// ICustomTypeDescriptor implementation.
3772 /// </devdoc>
3773 EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
3775 EventDescriptor evt = _primary.GetDefaultEvent();
3776 if (evt == null)
3778 evt = _secondary.GetDefaultEvent();
3781 return evt;
3784 /// <devdoc>
3785 /// ICustomTypeDescriptor implementation.
3786 /// </devdoc>
3787 PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
3789 PropertyDescriptor prop = _primary.GetDefaultProperty();
3790 if (prop == null)
3792 prop = _secondary.GetDefaultProperty();
3795 return prop;
3798 /// <devdoc>
3799 /// ICustomTypeDescriptor implementation.
3800 /// </devdoc>
3801 object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
3803 if (editorBaseType == null)
3805 throw new ArgumentNullException("editorBaseType");
3808 object editor = _primary.GetEditor(editorBaseType);
3809 if (editor == null)
3811 editor = _secondary.GetEditor(editorBaseType);
3814 return editor;
3817 /// <devdoc>
3818 /// ICustomTypeDescriptor implementation.
3819 /// </devdoc>
3820 EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
3822 EventDescriptorCollection events = _primary.GetEvents();
3823 if (events == null)
3825 events = _secondary.GetEvents();
3828 Debug.Assert(events != null, "Someone should have handled this");
3829 return events;
3832 /// <devdoc>
3833 /// ICustomTypeDescriptor implementation.
3834 /// </devdoc>
3835 EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
3837 EventDescriptorCollection events = _primary.GetEvents(attributes);
3838 if (events == null)
3840 events = _secondary.GetEvents(attributes);
3843 Debug.Assert(events != null, "Someone should have handled this");
3844 return events;
3847 /// <devdoc>
3848 /// ICustomTypeDescriptor implementation.
3849 /// </devdoc>
3850 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
3852 PropertyDescriptorCollection properties = _primary.GetProperties();
3853 if (properties == null)
3855 properties = _secondary.GetProperties();
3858 Debug.Assert(properties != null, "Someone should have handled this");
3859 return properties;
3862 /// <devdoc>
3863 /// ICustomTypeDescriptor implementation.
3864 /// </devdoc>
3865 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
3867 PropertyDescriptorCollection properties = _primary.GetProperties(attributes);
3868 if (properties == null)
3870 properties = _secondary.GetProperties(attributes);
3873 Debug.Assert(properties != null, "Someone should have handled this");
3874 return properties;
3877 /// <devdoc>
3878 /// ICustomTypeDescriptor implementation.
3879 /// </devdoc>
3880 object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
3882 object owner = _primary.GetPropertyOwner(pd);
3883 if (owner == null)
3885 owner = _secondary.GetPropertyOwner(pd);
3888 return owner;
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
3903 internal TypeDescriptionNode Next;
3904 internal TypeDescriptionProvider Provider;
3906 /// <devdoc>
3907 /// Creates a new type description node.
3908 /// </devdoc>
3909 internal TypeDescriptionNode(TypeDescriptionProvider provider)
3911 Provider = provider;
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)
3920 if (objectType == null)
3922 throw new ArgumentNullException("objectType");
3925 if (argTypes != null)
3927 if (args == null)
3929 throw new ArgumentNullException("args");
3932 if (argTypes.Length != args.Length)
3934 throw new ArgumentException(SR.GetString(SR.TypeDescriptorArgsCountMismatch));
3938 return Provider.CreateInstance(provider, objectType, argTypes, args);
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)
3947 if (instance == null)
3949 throw new ArgumentNullException("instance");
3952 return Provider.GetCache(instance);
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)
3961 if (instance == null)
3963 throw new ArgumentNullException("instance");
3966 return new DefaultExtendedTypeDescriptor(this, instance);
3969 protected internal override IExtenderProvider[] GetExtenderProviders(object instance)
3971 if (instance == null)
3973 throw new ArgumentNullException("instance");
3976 return Provider.GetExtenderProviders(instance);
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.
3985 /// If not overridden, the default implementation of this method will call
3986 /// GetTypeDescriptor.GetComponentName.
3987 /// </devdoc>
3988 public override string GetFullComponentName(object component)
3990 if (component == null)
3992 throw new ArgumentNullException("component");
3995 return Provider.GetFullComponentName(component);
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)
4004 if (objectType == null)
4006 throw new ArgumentNullException("objectType");
4009 return Provider.GetReflectionType(objectType, instance);
4012 public override Type GetRuntimeType(Type objectType)
4014 if (objectType == null)
4016 throw new ArgumentNullException("objectType");
4019 return Provider.GetRuntimeType(objectType);
4022 /// <devdoc>
4023 /// Implements GetTypeDescriptor. This creates a custom type
4024 /// descriptor that walks the linked list for each of its calls.
4025 /// </devdoc>
4027 [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters")]
4028 public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
4030 if (objectType == null)
4032 throw new ArgumentNullException("objectType");
4035 if (instance != null && !objectType.IsInstanceOfType(instance))
4037 throw new ArgumentException("instance");
4040 return new DefaultTypeDescriptor(this, objectType, instance);
4043 public override bool IsSupportedType(Type type)
4045 if (type == null)
4047 throw new ArgumentNullException("type");
4049 return Provider.IsSupportedType(type);
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
4058 private TypeDescriptionNode _node;
4059 private object _instance;
4061 /// <devdoc>
4062 /// Creates a new WalkingExtendedTypeDescriptor.
4063 /// </devdoc>
4064 internal DefaultExtendedTypeDescriptor(TypeDescriptionNode node, object instance)
4066 _node = node;
4067 _instance = instance;
4070 /// <devdoc>
4071 /// ICustomTypeDescriptor implementation.
4072 /// </devdoc>
4073 AttributeCollection ICustomTypeDescriptor.GetAttributes()
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
4079 TypeDescriptionProvider p = _node.Provider;
4080 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4082 if (rp != null) {
4083 return rp.GetExtendedAttributes(_instance);
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;
4093 /// <devdoc>
4094 /// ICustomTypeDescriptor implementation.
4095 /// </devdoc>
4096 string ICustomTypeDescriptor.GetClassName()
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
4102 TypeDescriptionProvider p = _node.Provider;
4103 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4105 if (rp != null) {
4106 return rp.GetExtendedClassName(_instance);
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;
4116 /// <devdoc>
4117 /// ICustomTypeDescriptor implementation.
4118 /// </devdoc>
4119 string ICustomTypeDescriptor.GetComponentName()
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
4125 TypeDescriptionProvider p = _node.Provider;
4126 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4128 if (rp != null) {
4129 return rp.GetExtendedComponentName(_instance);
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();
4137 /// <devdoc>
4138 /// ICustomTypeDescriptor implementation.
4139 /// </devdoc>
4140 TypeConverter ICustomTypeDescriptor.GetConverter()
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
4146 TypeDescriptionProvider p = _node.Provider;
4147 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4149 if (rp != null) {
4150 return rp.GetExtendedConverter(_instance);
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;
4160 /// <devdoc>
4161 /// ICustomTypeDescriptor implementation.
4162 /// </devdoc>
4163 EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
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
4169 TypeDescriptionProvider p = _node.Provider;
4170 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4172 if (rp != null) {
4173 return rp.GetExtendedDefaultEvent(_instance);
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();
4181 /// <devdoc>
4182 /// ICustomTypeDescriptor implementation.
4183 /// </devdoc>
4184 PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
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
4190 TypeDescriptionProvider p = _node.Provider;
4191 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4193 if (rp != null) {
4194 return rp.GetExtendedDefaultProperty(_instance);
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();
4202 /// <devdoc>
4203 /// ICustomTypeDescriptor implementation.
4204 /// </devdoc>
4205 object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
4207 if (editorBaseType == null)
4209 throw new ArgumentNullException("editorBaseType");
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
4216 TypeDescriptionProvider p = _node.Provider;
4217 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4219 if (rp != null) {
4220 return rp.GetExtendedEditor(_instance, editorBaseType);
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);
4228 /// <devdoc>
4229 /// ICustomTypeDescriptor implementation.
4230 /// </devdoc>
4231 EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
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
4237 TypeDescriptionProvider p = _node.Provider;
4238 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4240 if (rp != null) {
4241 return rp.GetExtendedEvents(_instance);
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;
4251 /// <devdoc>
4252 /// ICustomTypeDescriptor implementation.
4253 /// </devdoc>
4254 EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
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
4260 TypeDescriptionProvider p = _node.Provider;
4261 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
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;
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;
4279 /// <devdoc>
4280 /// ICustomTypeDescriptor implementation.
4281 /// </devdoc>
4282 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
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
4288 TypeDescriptionProvider p = _node.Provider;
4289 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4291 if (rp != null) {
4292 return rp.GetExtendedProperties(_instance);
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;
4302 /// <devdoc>
4303 /// ICustomTypeDescriptor implementation.
4304 /// </devdoc>
4305 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
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
4311 TypeDescriptionProvider p = _node.Provider;
4312 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
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;
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;
4330 /// <devdoc>
4331 /// ICustomTypeDescriptor implementation.
4332 /// </devdoc>
4333 object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
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
4339 TypeDescriptionProvider p = _node.Provider;
4340 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4342 if (rp != null) {
4343 return rp.GetExtendedPropertyOwner(_instance, pd);
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;
4354 /// <devdoc>
4355 /// The default type descriptor.
4356 /// </devdoc>
4357 private struct DefaultTypeDescriptor : ICustomTypeDescriptor
4359 private TypeDescriptionNode _node;
4360 private Type _objectType;
4361 private object _instance;
4363 /// <devdoc>
4364 /// Creates a new WalkingTypeDescriptor.
4365 /// </devdoc>
4366 internal DefaultTypeDescriptor(TypeDescriptionNode node, Type objectType, object instance)
4368 _node = node;
4369 _objectType = objectType;
4370 _instance = instance;
4373 /// <devdoc>
4374 /// ICustomTypeDescriptor implementation.
4375 /// </devdoc>
4376 AttributeCollection ICustomTypeDescriptor.GetAttributes()
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
4382 TypeDescriptionProvider p = _node.Provider;
4383 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4384 AttributeCollection attrs;
4386 if (rp != null) {
4387 attrs = rp.GetAttributes(_objectType);
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"));
4396 return attrs;
4399 /// <devdoc>
4400 /// ICustomTypeDescriptor implementation.
4401 /// </devdoc>
4402 string ICustomTypeDescriptor.GetClassName()
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
4408 TypeDescriptionProvider p = _node.Provider;
4409 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4410 string name;
4412 if (rp != null) {
4413 name = rp.GetClassName(_objectType);
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;
4422 return name;
4425 /// <devdoc>
4426 /// ICustomTypeDescriptor implementation.
4427 /// </devdoc>
4428 string ICustomTypeDescriptor.GetComponentName()
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
4434 TypeDescriptionProvider p = _node.Provider;
4435 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4436 string name;
4438 if (rp != null) {
4439 name = rp.GetComponentName(_objectType, _instance);
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();
4447 return name;
4450 /// <devdoc>
4451 /// ICustomTypeDescriptor implementation.
4452 /// </devdoc>
4453 TypeConverter ICustomTypeDescriptor.GetConverter()
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
4459 TypeDescriptionProvider p = _node.Provider;
4460 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4461 TypeConverter converter;
4463 if (rp != null) {
4464 converter = rp.GetConverter(_objectType, _instance);
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"));
4473 return converter;
4476 /// <devdoc>
4477 /// ICustomTypeDescriptor implementation.
4478 /// </devdoc>
4479 EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
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
4485 TypeDescriptionProvider p = _node.Provider;
4486 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4487 EventDescriptor defaultEvent;
4489 if (rp != null) {
4490 defaultEvent = rp.GetDefaultEvent(_objectType, _instance);
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();
4498 return defaultEvent;
4501 /// <devdoc>
4502 /// ICustomTypeDescriptor implementation.
4503 /// </devdoc>
4504 PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
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
4510 TypeDescriptionProvider p = _node.Provider;
4511 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4512 PropertyDescriptor defaultProperty;
4514 if (rp != null) {
4515 defaultProperty = rp.GetDefaultProperty(_objectType, _instance);
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();
4523 return defaultProperty;
4526 /// <devdoc>
4527 /// ICustomTypeDescriptor implementation.
4528 /// </devdoc>
4529 object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
4531 if (editorBaseType == null)
4533 throw new ArgumentNullException("editorBaseType");
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
4540 TypeDescriptionProvider p = _node.Provider;
4541 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4542 object editor;
4544 if (rp != null) {
4545 editor = rp.GetEditor(_objectType, _instance, editorBaseType);
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);
4553 return editor;
4556 /// <devdoc>
4557 /// ICustomTypeDescriptor implementation.
4558 /// </devdoc>
4559 EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
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
4565 TypeDescriptionProvider p = _node.Provider;
4566 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4567 EventDescriptorCollection events;
4569 if (rp != null) {
4570 events = rp.GetEvents(_objectType);
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"));
4579 return events;
4582 /// <devdoc>
4583 /// ICustomTypeDescriptor implementation.
4584 /// </devdoc>
4585 EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
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
4591 TypeDescriptionProvider p = _node.Provider;
4592 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4593 EventDescriptorCollection events;
4595 if (rp != null) {
4596 events = rp.GetEvents(_objectType);
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"));
4605 return events;
4608 /// <devdoc>
4609 /// ICustomTypeDescriptor implementation.
4610 /// </devdoc>
4611 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
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
4617 TypeDescriptionProvider p = _node.Provider;
4618 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4619 PropertyDescriptorCollection properties;
4621 if (rp != null) {
4622 properties = rp.GetProperties(_objectType);
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"));
4631 return properties;
4634 /// <devdoc>
4635 /// ICustomTypeDescriptor implementation.
4636 /// </devdoc>
4637 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
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
4643 TypeDescriptionProvider p = _node.Provider;
4644 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4645 PropertyDescriptorCollection properties;
4647 if (rp != null) {
4648 properties = rp.GetProperties(_objectType);
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"));
4657 return properties;
4660 /// <devdoc>
4661 /// ICustomTypeDescriptor implementation.
4662 /// </devdoc>
4663 object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
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
4669 TypeDescriptionProvider p = _node.Provider;
4670 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4671 object owner;
4673 if (rp != null) {
4674 owner = rp.GetPropertyOwner(_objectType, _instance, pd);
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;
4683 return owner;
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
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