1 //------------------------------------------------------------------------------
2 // <copyright file="TypeDescriptor.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
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;
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;
24 using System.Reflection;
25 using Microsoft.Win32;
26 using System.ComponentModel.Design;
27 using System.Diagnostics.CodeAnalysis;
28 using System.Runtime.Versioning;
31 /// Provides information about the properties and events
32 /// for a component. This class cannot be inherited.
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
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
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.");
58 private static BooleanSwitch EnableValidation = new BooleanSwitch("EnableValidation", "Enable type descriptor Whidbey->RTM validation");
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()
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")]
114 TypeDescriptionNode node = NodeFor(ComObjectType);
115 ComNativeDescriptionProvider provider = null;
119 provider = node.Provider as ComNativeDescriptionProvider;
122 while(node != null && provider == null);
124 if (provider != null)
126 return provider.Handler;
131 [PermissionSetAttribute(SecurityAction.LinkDemand, Name="FullTrust")]
134 TypeDescriptionNode node = NodeFor(ComObjectType);
136 while (node != null && !(node.Provider is ComNativeDescriptionProvider))
143 AddProvider(new ComNativeDescriptionProvider(value), ComObjectType);
147 ComNativeDescriptionProvider provider = (ComNativeDescriptionProvider)node.Provider;
148 provider.Handler = value;
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.
158 [EditorBrowsable(EditorBrowsableState.Advanced)]
159 public static Type ComObjectType
163 return typeof(TypeDescriptorComObject);
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.
171 [EditorBrowsable(EditorBrowsableState.Advanced)]
172 public static Type InterfaceType
176 return typeof(TypeDescriptorInterface);
181 /// This value increments each time someone refreshes or changes metadata.
183 internal static int MetadataVersion {
185 return _metadataVersion;
189 /// <include file='doc\TypeDescriptor.uex' path='docs/doc[@for="TypeDescriptor.Refreshed"]/*' />
191 /// Occurs when Refreshed is raised for a component.
193 public static event RefreshEventHandler Refreshed;
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.
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) {
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);
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.
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);
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.
259 [EditorBrowsable(EditorBrowsableState.Advanced)]
260 public static void AddEditorTable(Type editorBaseType, Hashtable table)
262 ReflectTypeDescriptionProvider.AddEditorTable(editorBaseType, table);
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
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");
285 throw new ArgumentNullException("type");
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);
295 _providerTable[type] = head;
296 _providerTypeTable.Clear();
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.
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");
324 // Get the root node, hook it up, and stuff it back into
325 // the provider cache.
328 refreshNeeded = _providerTable.ContainsKey(instance);
329 TypeDescriptionNode node = NodeFor(instance, true);
330 TypeDescriptionNode head = new TypeDescriptionNode(provider);
332 _providerTable.SetWeak(instance, head);
333 _providerTypeTable.Clear();
338 Refresh(instance, false);
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
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.
356 [EditorBrowsable(EditorBrowsableState.Advanced)]
357 public static void AddProviderTransparent(TypeDescriptionProvider provider, Type type)
359 if (provider == null)
361 throw new ArgumentNullException("provider");
366 throw new ArgumentNullException("type");
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();
377 AddProvider(provider, type);
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.
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.
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");
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();
415 AddProvider(provider, instance);
419 /// This method verifies that we have checked for the presence
420 /// of a default type description provider attribute for the
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))
443 lock (_internalSyncObject)
445 if (_defaultProviders.ContainsKey(type))
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 IntSecurity.FullReflection.Assert();
480 prov = (TypeDescriptionProvider)Activator.CreateInstance(providerType);
483 CodeAccessPermission.RevertAssert();
485 Trace("Providers : Default provider found : {0}", providerType.Name);
486 AddProvider(prov, type);
487 providerAdded = true;
491 // If we did not add a provider, check the base class.
492 if (!providerAdded) {
493 Type baseType = type.BaseType;
494 if (baseType != null && baseType != type) {
495 CheckDefaultProvider(baseType);
501 /// The CreateAssocation method creates an association between two objects.
502 /// Once an association is created, a designer or other filtering mechanism
503 /// can add properties that route to either object into the primary object's
504 /// property set. When a property invocation is made against the primary
505 /// object, GetAssocation will be called to resolve the actual object
506 /// instance that is related to its type parameter.
508 [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
509 [EditorBrowsable(EditorBrowsableState.Advanced)]
510 public static void CreateAssociation(object primary, object secondary)
514 throw new ArgumentNullException("primary");
517 if (secondary == null)
519 throw new ArgumentNullException("secondary");
522 if (primary == secondary)
524 throw new ArgumentException(SR.GetString(SR.TypeDescriptorSameAssociation));
527 if (_associationTable == null)
529 lock (_internalSyncObject)
531 if (_associationTable == null)
533 _associationTable = new WeakHashtable();
538 IList associations = (IList)_associationTable[primary];
540 if (associations == null)
542 lock (_associationTable)
544 associations = (IList)_associationTable[primary];
545 if (associations == null)
547 associations = new ArrayList(4);
548 _associationTable.SetWeak(primary, associations);
554 for (int idx = associations.Count - 1; idx >= 0; idx--)
556 WeakReference r = (WeakReference)associations[idx];
557 if (r.IsAlive && r.Target == secondary)
559 throw new ArgumentException(SR.GetString(SR.TypeDescriptorAlreadyAssociated));
566 associations.Add(new WeakReference(secondary));
571 /// Creates an instance of the designer associated with the
572 /// specified component.
574 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2113:SecureLateBindingMethods")]
575 public static IDesigner CreateDesigner(IComponent component, Type designerBaseType)
577 Type designerType = null;
578 IDesigner designer = null;
580 // Get the set of attributes for this type
582 AttributeCollection attributes = GetAttributes(component);
584 for (int i = 0; i < attributes.Count; i++)
586 DesignerAttribute da = attributes[i] as DesignerAttribute;
589 Type attributeBaseType = Type.GetType(da.DesignerBaseTypeName);
590 if (attributeBaseType != null && attributeBaseType == designerBaseType)
592 ISite site = component.Site;
593 bool foundService = false;
597 ITypeResolutionService tr = (ITypeResolutionService)site.GetService(typeof(ITypeResolutionService));
601 designerType = tr.GetType(da.DesignerTypeName);
607 designerType = Type.GetType(da.DesignerTypeName);
610 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 + "'");
611 if (designerType != null)
619 if (designerType != null)
621 designer = (IDesigner)SecurityUtils.SecureCreateInstance(designerType, null, true);
628 /// This dynamically binds an EventDescriptor to a type.
630 [ReflectionPermission(SecurityAction.LinkDemand, Flags=ReflectionPermissionFlag.MemberAccess)]
631 public static EventDescriptor CreateEvent(Type componentType, string name, Type type, params Attribute[] attributes)
633 return new ReflectEventDescriptor(componentType, name, type, attributes);
637 /// This creates a new event descriptor identical to an existing event descriptor. The new event descriptor
638 /// has the specified metadata attributes merged with the existing metadata attributes.
640 [ReflectionPermission(SecurityAction.LinkDemand, Flags=ReflectionPermissionFlag.MemberAccess)]
641 public static EventDescriptor CreateEvent(Type componentType, EventDescriptor oldEventDescriptor, params Attribute[] attributes)
643 return new ReflectEventDescriptor(componentType, oldEventDescriptor, attributes);
647 /// This method will search internal tables within TypeDescriptor for
648 /// a TypeDescriptionProvider object that is associated with the given
649 /// data type. If it finds one, it will delegate the call to that object.
651 public static object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)
653 if (objectType == null)
655 throw new ArgumentNullException("objectType");
658 if (argTypes != null)
662 throw new ArgumentNullException("args");
665 if (argTypes.Length != args.Length)
667 throw new ArgumentException(SR.GetString(SR.TypeDescriptorArgsCountMismatch));
671 object instance = null;
673 // See if the provider wants to offer a TypeDescriptionProvider to delegate to. This allows
674 // a caller to have complete control over all object instantiation.
675 if (provider != null) {
676 TypeDescriptionProvider p = provider.GetService(typeof(TypeDescriptionProvider)) as TypeDescriptionProvider;
678 instance = p.CreateInstance(provider, objectType, argTypes, args);
682 if (instance == null) {
683 instance = NodeFor(objectType).CreateInstance(provider, objectType, argTypes, args);
690 /// This dynamically binds a PropertyDescriptor to a type.
692 [ReflectionPermission(SecurityAction.LinkDemand, Flags=ReflectionPermissionFlag.MemberAccess)]
693 public static PropertyDescriptor CreateProperty(Type componentType, string name, Type type, params Attribute[] attributes)
695 return new ReflectPropertyDescriptor(componentType, name, type, attributes);
699 /// This creates a new property descriptor identical to an existing property descriptor. The new property descriptor
700 /// has the specified metadata attributes merged with the existing metadata attributes.
702 [ReflectionPermission(SecurityAction.LinkDemand, Flags=ReflectionPermissionFlag.MemberAccess)]
703 public static PropertyDescriptor CreateProperty(Type componentType, PropertyDescriptor oldPropertyDescriptor, params Attribute[] attributes)
706 // We must do some special case work here for extended properties. If the old property descriptor is really
707 // an extender property that is being surfaced on a component as a normal property, then we must
708 // do work here or else ReflectPropertyDescriptor will fail to resolve the get and set methods. We check
709 // for the necessary ExtenderProvidedPropertyAttribute and if we find it, we create an
710 // ExtendedPropertyDescriptor instead. We only do this if the component class is the same, since the user
711 // may want to re-route the property to a different target.
713 if (componentType == oldPropertyDescriptor.ComponentType)
715 ExtenderProvidedPropertyAttribute attr = (ExtenderProvidedPropertyAttribute)
716 oldPropertyDescriptor.Attributes[
717 typeof(ExtenderProvidedPropertyAttribute)];
719 ReflectPropertyDescriptor reflectDesc = attr.ExtenderProperty as ReflectPropertyDescriptor;
720 if (reflectDesc != null)
722 return new ExtendedPropertyDescriptor(oldPropertyDescriptor, attributes);
727 DebugReflectPropertyDescriptor debugReflectDesc = attr.ExtenderProperty as DebugReflectPropertyDescriptor;
728 if (debugReflectDesc != null)
730 return new DebugExtendedPropertyDescriptor(oldPropertyDescriptor, attributes);
736 // This is either a normal prop or the caller has changed target classes.
738 return new ReflectPropertyDescriptor(componentType, oldPropertyDescriptor, attributes);
742 /// Debug code that runs the output of a TypeDescriptor query into a debug
743 /// type descriptor that uses the V1.0 algorithm. This code will assert
744 /// if the two type descriptors do not agree. This method returns true if
745 /// validation should be performed for the type.
748 private static bool DebugShouldValidate(object key)
750 // Check our switch first.
752 if (EnableValidation.Enabled)
756 // We only validate if there are no custom providers all the way
757 // up the class chain.
758 TypeDescriptionNode node = _providerTable[key] as TypeDescriptionNode;
759 if (node != null && !(node.Provider is ReflectTypeDescriptionProvider))
766 key = GetNodeForBaseType((Type)key);
771 if (((Type)key).IsCOMObject)
784 /// Debug code that runs the output of a TypeDescriptor query into a debug
785 /// type descriptor that uses the V1.0 algorithm. This code will assert
786 /// if the two type descriptors do not agree.
788 [Conditional("DEBUG")]
789 private static void DebugValidate(Type type, AttributeCollection attributes, AttributeCollection debugAttributes)
792 if (!DebugShouldValidate(type)) return;
793 DebugValidate(attributes, debugAttributes);
798 /// Debug code that runs the output of a TypeDescriptor query into a debug
799 /// type descriptor that uses the V1.0 algorithm. This code will assert
800 /// if the two type descriptors do not agree.
802 [Conditional("DEBUG")]
803 private static void DebugValidate(AttributeCollection attributes, AttributeCollection debugAttributes)
807 if (attributes.Count >= debugAttributes.Count)
809 foreach(Attribute a in attributes)
811 if (!(a is GuidAttribute) && !(a is ComVisibleAttribute))
814 bool typeFound = false;
816 // Many attributes don't implement .Equals correctly,
817 // so they will fail an equality check. But we want to
818 // make sure that common ones like Browsable and ReadOnly
819 // were correctly picked up. So only check the ones in
821 if (!a.GetType().FullName.StartsWith("System.Component"))
829 foreach(Attribute b in debugAttributes)
831 if (!typeFound && a.GetType() == b.GetType())
836 // Semitrust may throw here.
853 if (!found && !a.IsDefaultAttribute())
857 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));
861 Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Attribute {0} should not exist", a.GetType().Name));
869 foreach(Attribute b in debugAttributes)
871 // We skip all interop attributes because interface merging has changed on purpose.
872 if (!(b is GuidAttribute) && !(b is ComVisibleAttribute) && !(b is InterfaceTypeAttribute) && !(b is ReadOnlyAttribute))
875 bool typeFound = false;
877 // Many attributes don't implement .Equals correctly,
878 // so they will fail an equality check. But we want to
879 // make sure that common ones like Browsable and ReadOnly
880 // were correctly picked up. So only check the ones in
882 if (!b.GetType().FullName.StartsWith("System.Component"))
890 foreach(Attribute a in attributes)
892 if (!typeFound && a.GetType() == b.GetType())
897 // Semitrust may throw here.
914 if (!found && !b.IsDefaultAttribute())
918 Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Attribute {0} should exist", b.GetType().Name));
928 /// Debug code that runs the output of a TypeDescriptor query into a debug
929 /// type descriptor that uses the V1.0 algorithm. This code will assert
930 /// if the two type descriptors do not agree.
932 [Conditional("DEBUG")]
933 private static void DebugValidate(AttributeCollection attributes, Type type)
936 if (!DebugShouldValidate(type)) return;
937 AttributeCollection debugAttributes = DebugTypeDescriptor.GetAttributes(type);
938 DebugValidate(attributes, debugAttributes);
943 /// Debug code that runs the output of a TypeDescriptor query into a debug
944 /// type descriptor that uses the V1.0 algorithm. This code will assert
945 /// if the two type descriptors do not agree.
947 [Conditional("DEBUG")]
948 private static void DebugValidate(AttributeCollection attributes, object instance, bool noCustomTypeDesc)
951 if (!DebugShouldValidate(instance)) return;
952 AttributeCollection debugAttributes = DebugTypeDescriptor.GetAttributes(instance, noCustomTypeDesc);
953 DebugValidate(attributes, debugAttributes);
958 /// Debug code that runs the output of a TypeDescriptor query into a debug
959 /// type descriptor that uses the V1.0 algorithm. This code will assert
960 /// if the two type descriptors do not agree.
962 [Conditional("DEBUG")]
963 private static void DebugValidate(TypeConverter converter, Type type)
966 if (!DebugShouldValidate(type)) return;
967 TypeConverter debugConverter = DebugTypeDescriptor.GetConverter(type);
968 Debug.Assert(debugConverter.GetType() == converter.GetType(), "TypeDescriptor engine Validation Failure.");
973 /// Debug code that runs the output of a TypeDescriptor query into a debug
974 /// type descriptor that uses the V1.0 algorithm. This code will assert
975 /// if the two type descriptors do not agree.
977 [Conditional("DEBUG")]
978 private static void DebugValidate(TypeConverter converter, object instance, bool noCustomTypeDesc)
981 if (!DebugShouldValidate(instance)) return;
982 TypeConverter debugConverter = DebugTypeDescriptor.GetConverter(instance, noCustomTypeDesc);
983 Debug.Assert(debugConverter.GetType() == converter.GetType(), "TypeDescriptor engine Validation Failure.");
988 /// Debug code that runs the output of a TypeDescriptor query into a debug
989 /// type descriptor that uses the V1.0 algorithm. This code will assert
990 /// if the two type descriptors do not agree.
992 [Conditional("DEBUG")]
993 private static void DebugValidate(EventDescriptorCollection events, Type type, Attribute[] attributes)
996 if (!DebugShouldValidate(type)) return;
997 EventDescriptorCollection debugEvents = DebugTypeDescriptor.GetEvents(type, attributes);
998 Debug.Assert(debugEvents.Count == events.Count, "TypeDescriptor engine Validation Failure. Event counts differ.");
999 foreach(EventDescriptor debugEvt in debugEvents)
1001 EventDescriptor evt = null;
1003 foreach(EventDescriptor realEvt in events)
1005 if (realEvt.Name.Equals(debugEvt.Name) && realEvt.EventType == debugEvt.EventType && realEvt.ComponentType == debugEvt.ComponentType)
1012 Debug.Assert(evt != null, "TypeDescriptor engine Validation Failure. Event " + debugEvt.Name + " does not exist or is of the wrong type.");
1015 AttributeCollection attrs = evt.Attributes;
1016 if (attrs[typeof(AttributeProviderAttribute)] == null)
1018 AttributeCollection debugAttrs = debugEvt.Attributes;
1019 DebugValidate(evt.EventType, attrs, debugAttrs);
1027 /// Debug code that runs the output of a TypeDescriptor query into a debug
1028 /// type descriptor that uses the V1.0 algorithm. This code will assert
1029 /// if the two type descriptors do not agree.
1031 [Conditional("DEBUG")]
1032 private static void DebugValidate(EventDescriptorCollection events, object instance, Attribute[] attributes, bool noCustomTypeDesc)
1035 if (!DebugShouldValidate(instance)) return;
1036 EventDescriptorCollection debugEvents = DebugTypeDescriptor.GetEvents(instance, attributes, noCustomTypeDesc);
1037 Debug.Assert(debugEvents.Count == events.Count, "TypeDescriptor engine Validation Failure. Event counts differ.");
1038 foreach(EventDescriptor debugEvt in debugEvents)
1040 EventDescriptor evt = null;
1042 foreach(EventDescriptor realEvt in events)
1044 if (realEvt.Name.Equals(debugEvt.Name) && realEvt.EventType == debugEvt.EventType && realEvt.ComponentType == debugEvt.ComponentType)
1051 Debug.Assert(evt != null, "TypeDescriptor engine Validation Failure. Event " + debugEvt.Name + " does not exist or is of the wrong type.");
1054 AttributeCollection attrs = evt.Attributes;
1055 if (attrs[typeof(AttributeProviderAttribute)] == null)
1057 AttributeCollection debugAttrs = debugEvt.Attributes;
1058 DebugValidate(evt.EventType, attrs, debugAttrs);
1066 /// Debug code that runs the output of a TypeDescriptor query into a debug
1067 /// type descriptor that uses the V1.0 algorithm. This code will assert
1068 /// if the two type descriptors do not agree.
1070 [Conditional("DEBUG")]
1071 private static void DebugValidate(PropertyDescriptorCollection properties, Type type, Attribute[] attributes)
1074 if (!DebugShouldValidate(type)) return;
1075 PropertyDescriptorCollection debugProperties = DebugTypeDescriptor.GetProperties(type, attributes);
1077 if (debugProperties.Count > properties.Count)
1079 foreach(PropertyDescriptor debugProp in debugProperties)
1081 PropertyDescriptor prop = null;
1083 foreach(PropertyDescriptor realProp in properties)
1085 if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
1094 Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should exist.", debugProp.Name, debugProp.GetType().Name));
1098 else if (properties.Count > debugProperties.Count)
1100 foreach(PropertyDescriptor prop in properties)
1102 PropertyDescriptor debugProp = null;
1104 foreach(PropertyDescriptor realProp in debugProperties)
1106 if (realProp.Name.Equals(prop.Name) && realProp.PropertyType == prop.PropertyType && realProp.ComponentType == prop.ComponentType)
1108 debugProp = realProp;
1113 if (debugProp == null)
1115 Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should not exist.", prop.Name, prop.GetType().Name));
1121 foreach(PropertyDescriptor debugProp in debugProperties)
1123 PropertyDescriptor prop = null;
1125 foreach(PropertyDescriptor realProp in properties)
1127 if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
1134 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));
1137 AttributeCollection attrs = prop.Attributes;
1138 if (attrs[typeof(AttributeProviderAttribute)] == null)
1140 AttributeCollection debugAttrs = debugProp.Attributes;
1141 DebugValidate(prop.PropertyType, attrs, debugAttrs);
1150 /// Debug code that runs the output of a TypeDescriptor query into a debug
1151 /// type descriptor that uses the V1.0 algorithm. This code will assert
1152 /// if the two type descriptors do not agree.
1154 [Conditional("DEBUG")]
1155 private static void DebugValidate(PropertyDescriptorCollection properties, object instance, Attribute[] attributes, bool noCustomTypeDesc)
1158 if (!DebugShouldValidate(instance)) return;
1159 PropertyDescriptorCollection debugProperties = DebugTypeDescriptor.GetProperties(instance, attributes, noCustomTypeDesc);
1161 if (debugProperties.Count > properties.Count)
1163 foreach(PropertyDescriptor debugProp in debugProperties)
1165 PropertyDescriptor prop = null;
1167 foreach(PropertyDescriptor realProp in properties)
1169 if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
1178 Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should exist.", debugProp.Name, debugProp.GetType().Name));
1182 else if (properties.Count > debugProperties.Count)
1184 foreach(PropertyDescriptor prop in properties)
1186 PropertyDescriptor debugProp = null;
1188 foreach(PropertyDescriptor realProp in debugProperties)
1190 if (realProp.Name.Equals(prop.Name) && realProp.PropertyType == prop.PropertyType && realProp.ComponentType == prop.ComponentType)
1192 debugProp = realProp;
1197 if (debugProp == null)
1199 Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should not exist.", prop.Name, prop.GetType().Name));
1205 foreach(PropertyDescriptor debugProp in debugProperties)
1207 PropertyDescriptor prop = null;
1209 foreach(PropertyDescriptor realProp in properties)
1211 if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
1218 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));
1221 AttributeCollection attrs = prop.Attributes;
1222 if (attrs[typeof(AttributeProviderAttribute)] == null)
1224 AttributeCollection debugAttrs = debugProp.Attributes;
1225 DebugValidate(prop.PropertyType, attrs, debugAttrs);
1234 /// This API is used to remove any members from the given
1235 /// collection that do not match the attribute array. If members
1236 /// need to be removed, a new ArrayList wil be created that
1237 /// contains only the remaining members. The API returns
1238 /// NULL if it did not need to filter any members.
1240 private static ArrayList FilterMembers(IList members, Attribute[] attributes) {
1241 ArrayList newMembers = null;
1242 int memberCount = members.Count;
1244 for (int idx = 0; idx < memberCount; idx++) {
1248 for (int attrIdx = 0; attrIdx < attributes.Length; attrIdx++) {
1249 if (ShouldHideMember((MemberDescriptor)members[idx], attributes[attrIdx])) {
1256 // We have to hide. If this is the first time, we need to init
1257 // newMembers to have all the valid members we have previously
1259 if (newMembers == null) {
1260 newMembers = new ArrayList(memberCount);
1261 for (int validIdx = 0; validIdx < idx; validIdx++) {
1262 newMembers.Add(members[validIdx]);
1266 else if (newMembers != null) {
1267 newMembers.Add(members[idx]);
1276 /// The GetAssociation method returns the correct object to invoke
1277 /// for the requested type. It never returns null.
1279 [EditorBrowsable(EditorBrowsableState.Advanced)]
1280 public static object GetAssociation(Type type, object primary)
1284 throw new ArgumentNullException("type");
1287 if (primary == null)
1289 throw new ArgumentNullException("primary");
1292 object associatedObject = primary;
1294 if (!type.IsInstanceOfType(primary))
1296 // Check our association table for a match.
1298 Hashtable assocTable = _associationTable;
1299 if (assocTable != null)
1301 IList associations = (IList)assocTable[primary];
1302 if (associations != null)
1306 for (int idx = associations.Count - 1; idx >= 0; idx--)
1308 // Look for an associated object that has a type that
1309 // matches the given type.
1311 WeakReference weakRef = (WeakReference)associations[idx];
1312 object secondary = weakRef.Target;
1313 if (secondary == null)
1315 Trace("Associations : Removing dead reference in assocation table");
1316 associations.RemoveAt(idx);
1318 else if (type.IsInstanceOfType(secondary))
1320 Trace("Associations : Associated {0} to {1}", primary.GetType().Name, secondary.GetType().Name);
1321 associatedObject = secondary;
1328 // Not in our table. We have a default association with a designer
1329 // if that designer is a component.
1331 if (associatedObject == primary)
1333 IComponent component = primary as IComponent;
1334 if (component != null)
1336 ISite site = component.Site;
1338 if (site != null && site.DesignMode)
1340 IDesignerHost host = site.GetService(typeof(IDesignerHost)) as IDesignerHost;
1343 object designer = host.GetDesigner(component);
1345 // We only use the designer if it has a compatible class. If we
1346 // got here, we're probably hosed because the user just passed in
1347 // an object that this PropertyDescriptor can't munch on, but it's
1348 // clearer to use that object instance instead of it's designer.
1350 if (designer != null && type.IsInstanceOfType(designer))
1352 Trace("Associations : Associated {0} to {1}", primary.GetType().Name, designer.GetType().Name);
1353 associatedObject = designer;
1361 return associatedObject;
1365 /// Gets a collection of attributes for the specified type of component.
1367 public static AttributeCollection GetAttributes(Type componentType)
1369 if (componentType == null)
1371 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
1372 return new AttributeCollection((Attribute[])null);
1375 AttributeCollection attributes = GetDescriptor(componentType, "componentType").GetAttributes();
1376 DebugValidate(attributes, componentType);
1381 /// Gets a collection of attributes for the specified component.
1383 public static AttributeCollection GetAttributes(object component)
1385 return GetAttributes(component, false);
1389 /// Gets a collection of attributes for the specified component.
1391 [EditorBrowsable(EditorBrowsableState.Advanced)]
1392 public static AttributeCollection GetAttributes(object component, bool noCustomTypeDesc)
1394 if (component == null)
1396 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
1397 return new AttributeCollection((Attribute[])null);
1400 // We create a sort of pipeline for mucking with metadata. The pipeline
1401 // goes through the following process:
1403 // 1. Merge metadata from extenders.
1404 // 2. Allow services to filter the metadata
1405 // 3. If an attribute filter was specified, apply that.
1407 // The goal here is speed. We get speed by not copying or
1408 // allocating memory. We do this by allowing each phase of the
1409 // pipeline to cache its data in the object cache. If
1410 // a phase makes a change to the results, this change must cause
1411 // successive phases to recompute their results as well. "Results" is
1412 // always a collection, and the various stages of the pipeline may
1413 // replace or modify this collection (depending on if it's a
1414 // read-only IList or not). It is possible for the orignal
1415 // descriptor or attribute collection to pass through the entire
1416 // pipeline without modification.
1418 ICustomTypeDescriptor typeDesc = GetDescriptor(component, noCustomTypeDesc);
1419 ICollection results = typeDesc.GetAttributes();
1421 // If we are handed a custom type descriptor we have several choices of action
1422 // we can take. If noCustomTypeDesc is true, it means that the custom type
1423 // descriptor is trying to find a baseline set of properties. In this case
1424 // we should merge in extended properties, but we do not let designers filter
1425 // because we're not done with the property set yet. If noCustomTypeDesc
1426 // is false, we don't do extender properties because the custom type descriptor
1427 // has already added them. In this case, we are doing a final pass so we
1428 // want to apply filtering. Finally, if the incoming object is not a custom
1429 // type descriptor, we do extenders and the filter.
1431 if (component is ICustomTypeDescriptor)
1433 if (noCustomTypeDesc)
1435 ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
1436 if (extDesc != null)
1438 ICollection extResults = extDesc.GetAttributes();
1439 results = PipelineMerge(PIPELINE_ATTRIBUTES, results, extResults, component, null);
1444 results = PipelineFilter(PIPELINE_ATTRIBUTES, results, component, null);
1449 IDictionary cache = GetCache(component);
1451 results = PipelineInitialize(PIPELINE_ATTRIBUTES, results, cache);
1453 ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
1454 if (extDesc != null)
1456 ICollection extResults = extDesc.GetAttributes();
1457 results = PipelineMerge(PIPELINE_ATTRIBUTES, results, extResults, component, cache);
1460 results = PipelineFilter(PIPELINE_ATTRIBUTES, results, component, cache);
1463 AttributeCollection attrs = results as AttributeCollection;
1466 Trace("Attributes : Allocated new attribute collection for {0}", component.GetType().Name);
1467 Attribute[] attrArray = new Attribute[results.Count];
1468 results.CopyTo(attrArray, 0);
1469 attrs = new AttributeCollection(attrArray);
1472 DebugValidate(attrs, component, noCustomTypeDesc);
1477 /// Helper function to obtain a cache for the given object.
1479 internal static IDictionary GetCache(object instance)
1481 return NodeFor(instance).GetCache(instance);
1485 /// Gets the name of the class for the specified component.
1487 public static string GetClassName(object component)
1489 return GetClassName(component, false);
1493 /// Gets the name of the class for the specified component.
1495 [EditorBrowsable(EditorBrowsableState.Advanced)]
1496 public static string GetClassName(object component, bool noCustomTypeDesc)
1498 return GetDescriptor(component, noCustomTypeDesc).GetClassName();
1502 /// Gets the name of the class for the specified type.
1504 public static string GetClassName(Type componentType)
1506 return GetDescriptor(componentType, "componentType").GetClassName();
1510 /// The name of the class for the specified component.
1512 public static string GetComponentName(object component)
1514 return GetComponentName(component, false);
1518 /// Gets the name of the class for the specified component.
1520 [EditorBrowsable(EditorBrowsableState.Advanced)]
1521 public static string GetComponentName(object component, bool noCustomTypeDesc)
1523 return GetDescriptor(component, noCustomTypeDesc).GetComponentName();
1527 /// Gets a type converter for the type of the specified component.
1529 public static TypeConverter GetConverter(object component)
1531 return GetConverter(component, false);
1535 /// Gets a type converter for the type of the specified component.
1537 [EditorBrowsable(EditorBrowsableState.Advanced)]
1538 public static TypeConverter GetConverter(object component, bool noCustomTypeDesc)
1540 TypeConverter converter = GetDescriptor(component, noCustomTypeDesc).GetConverter();
1541 DebugValidate(converter, component, noCustomTypeDesc);
1546 /// Gets a type converter for the specified type.
1548 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
1549 public static TypeConverter GetConverter(Type type)
1551 TypeConverter converter = GetDescriptor(type, "type").GetConverter();
1552 DebugValidate(converter, type);
1557 /// Gets the default event for the specified type of component.
1559 public static EventDescriptor GetDefaultEvent(Type componentType)
1561 if (componentType == null)
1563 Debug.Fail("COMPAT: Returning null, but you should not pass null here");
1567 return GetDescriptor(componentType, "componentType").GetDefaultEvent();
1571 /// Gets the default event for the specified component.
1573 public static EventDescriptor GetDefaultEvent(object component)
1575 return GetDefaultEvent(component, false);
1579 /// Gets the default event for a component.
1581 [EditorBrowsable(EditorBrowsableState.Advanced)]
1582 public static EventDescriptor GetDefaultEvent(object component, bool noCustomTypeDesc)
1584 if (component == null)
1586 Debug.Fail("COMPAT: Returning null, but you should not pass null here");
1590 return GetDescriptor(component, noCustomTypeDesc).GetDefaultEvent();
1594 /// Gets the default property for the specified type of component.
1596 public static PropertyDescriptor GetDefaultProperty(Type componentType)
1598 if (componentType == null)
1600 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
1604 return GetDescriptor(componentType, "componentType").GetDefaultProperty();
1608 /// Gets the default property for the specified component.
1610 public static PropertyDescriptor GetDefaultProperty(object component)
1612 return GetDefaultProperty(component, false);
1616 /// Gets the default property for the specified component.
1618 [EditorBrowsable(EditorBrowsableState.Advanced)]
1619 public static PropertyDescriptor GetDefaultProperty(object component, bool noCustomTypeDesc)
1621 if (component == null)
1623 Debug.Fail("COMPAT: Returning null, but you should not pass null here");
1627 return GetDescriptor(component, noCustomTypeDesc).GetDefaultProperty();
1631 /// Returns a custom type descriptor for the given type.
1632 /// Performs arg checking so callers don't have to.
1634 internal static ICustomTypeDescriptor GetDescriptor(Type type, string typeName)
1638 throw new ArgumentNullException(typeName);
1641 return NodeFor(type).GetTypeDescriptor(type);
1645 /// Returns a custom type descriptor for the given instance.
1646 /// Performs arg checking so callers don't have to. This
1647 /// will call through to instance if it is a custom type
1650 internal static ICustomTypeDescriptor GetDescriptor(object component, bool noCustomTypeDesc)
1652 if (component == null)
1654 throw new ArgumentException("component");
1657 if (component is IUnimplemented) {
1658 throw new NotSupportedException(SR.GetString(SR.TypeDescriptorUnsupportedRemoteObject, component.GetType().FullName));
1662 ICustomTypeDescriptor desc = NodeFor(component).GetTypeDescriptor(component);
1663 ICustomTypeDescriptor d = component as ICustomTypeDescriptor;
1664 if (!noCustomTypeDesc && d != null)
1666 desc = new MergedTypeDescriptor(d, desc);
1673 /// Returns an extended custom type descriptor for the given instance.
1675 internal static ICustomTypeDescriptor GetExtendedDescriptor(object component)
1677 if (component == null)
1679 throw new ArgumentException("component");
1682 return NodeFor(component).GetExtendedTypeDescriptor(component);
1686 /// Gets an editor with the specified base type for the
1687 /// specified component.
1689 public static object GetEditor(object component, Type editorBaseType)
1691 return GetEditor(component, editorBaseType, false);
1695 /// Gets an editor with the specified base type for the
1696 /// specified component.
1698 [EditorBrowsable(EditorBrowsableState.Advanced)]
1699 public static object GetEditor(object component, Type editorBaseType, bool noCustomTypeDesc)
1701 if (editorBaseType == null)
1703 throw new ArgumentNullException("editorBaseType");
1706 return GetDescriptor(component, noCustomTypeDesc).GetEditor(editorBaseType);
1710 /// Gets an editor with the specified base type for the specified type.
1712 public static object GetEditor(Type type, Type editorBaseType)
1714 if (editorBaseType == null)
1716 throw new ArgumentNullException("editorBaseType");
1719 return GetDescriptor(type, "type").GetEditor(editorBaseType);
1723 /// Gets a collection of events for a specified type of component.
1725 public static EventDescriptorCollection GetEvents(Type componentType)
1727 if (componentType == null)
1729 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
1730 return new EventDescriptorCollection(null, true);
1733 return GetDescriptor(componentType, "componentType").GetEvents();
1737 /// Gets a collection of events for a specified type of
1738 /// component using a specified array of attributes as a filter.
1740 public static EventDescriptorCollection GetEvents(Type componentType, Attribute[] attributes)
1742 if (componentType == null)
1744 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
1745 return new EventDescriptorCollection(null, true);
1748 EventDescriptorCollection events = GetDescriptor(componentType, "componentType").GetEvents(attributes);
1750 if (attributes != null && attributes.Length > 0) {
1751 ArrayList filteredEvents = FilterMembers(events, attributes);
1752 if (filteredEvents != null) {
1753 events = new EventDescriptorCollection((EventDescriptor[])filteredEvents.ToArray(typeof(EventDescriptor)), true);
1757 DebugValidate(events, componentType, attributes);
1762 /// Gets a collection of events for a specified component.
1764 public static EventDescriptorCollection GetEvents(object component)
1766 return GetEvents(component, null, false);
1770 /// Gets a collection of events for a specified component.
1772 [EditorBrowsable(EditorBrowsableState.Advanced)]
1773 public static EventDescriptorCollection GetEvents(object component, bool noCustomTypeDesc)
1775 return GetEvents(component, null, noCustomTypeDesc);
1779 /// Gets a collection of events for a specified component
1780 /// using a specified array of attributes as a filter.
1782 public static EventDescriptorCollection GetEvents(object component, Attribute[] attributes)
1784 return GetEvents(component, attributes, false);
1788 /// Gets a collection of events for a specified component
1789 /// using a specified array of attributes as a filter.
1791 [EditorBrowsable(EditorBrowsableState.Advanced)]
1792 public static EventDescriptorCollection GetEvents(object component, Attribute[] attributes, bool noCustomTypeDesc)
1794 if (component == null)
1796 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
1797 return new EventDescriptorCollection(null, true);
1800 // We create a sort of pipeline for mucking with metadata. The pipeline
1801 // goes through the following process:
1803 // 1. Merge metadata from extenders.
1804 // 2. Allow services to filter the metadata
1805 // 3. If an attribute filter was specified, apply that.
1807 // The goal here is speed. We get speed by not copying or
1808 // allocating memory. We do this by allowing each phase of the
1809 // pipeline to cache its data in the object cache. If
1810 // a phase makes a change to the results, this change must cause
1811 // successive phases to recompute their results as well. "Results" is
1812 // always a collection, and the various stages of the pipeline may
1813 // replace or modify this collection (depending on if it's a
1814 // read-only IList or not). It is possible for the orignal
1815 // descriptor or attribute collection to pass through the entire
1816 // pipeline without modification.
1818 ICustomTypeDescriptor typeDesc = GetDescriptor(component, noCustomTypeDesc);
1819 ICollection results;
1821 // If we are handed a custom type descriptor we have several choices of action
1822 // we can take. If noCustomTypeDesc is true, it means that the custom type
1823 // descriptor is trying to find a baseline set of events. In this case
1824 // we should merge in extended events, but we do not let designers filter
1825 // because we're not done with the event set yet. If noCustomTypeDesc
1826 // is false, we don't do extender events because the custom type descriptor
1827 // has already added them. In this case, we are doing a final pass so we
1828 // want to apply filtering. Finally, if the incoming object is not a custom
1829 // type descriptor, we do extenders and the filter.
1831 if (component is ICustomTypeDescriptor)
1833 results = typeDesc.GetEvents(attributes);
1834 if (noCustomTypeDesc)
1836 ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
1837 if (extDesc != null)
1839 ICollection extResults = extDesc.GetEvents(attributes);
1840 results = PipelineMerge(PIPELINE_EVENTS, results, extResults, component, null);
1845 results = PipelineFilter(PIPELINE_EVENTS, results, component, null);
1846 results = PipelineAttributeFilter(PIPELINE_EVENTS, results, attributes, component, null);
1851 IDictionary cache = GetCache(component);
1852 results = typeDesc.GetEvents(attributes);
1853 results = PipelineInitialize(PIPELINE_EVENTS, results, cache);
1854 ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
1855 if (extDesc != null)
1857 ICollection extResults = extDesc.GetEvents(attributes);
1858 results = PipelineMerge(PIPELINE_EVENTS, results, extResults, component, cache);
1861 results = PipelineFilter(PIPELINE_EVENTS, results, component, cache);
1862 results = PipelineAttributeFilter(PIPELINE_EVENTS, results, attributes, component, cache);
1865 EventDescriptorCollection evts = results as EventDescriptorCollection;
1868 Trace("Events : Allocated new event collection for {0}", component.GetType().Name);
1869 EventDescriptor[] eventArray = new EventDescriptor[results.Count];
1870 results.CopyTo(eventArray, 0);
1871 evts = new EventDescriptorCollection(eventArray, true);
1874 DebugValidate(evts, component, attributes, noCustomTypeDesc);
1880 /// This method is invoked during filtering when a name
1881 /// collision is encountered between two properties or events. This returns
1882 /// a suffix that can be appended to the name to make
1883 /// it unique. This will first attempt ot use the name of the
1884 /// extender. Failing that it will fall back to a static
1885 /// index that is continually incremented.
1887 private static string GetExtenderCollisionSuffix(MemberDescriptor member)
1889 string suffix = null;
1891 ExtenderProvidedPropertyAttribute exAttr = member.Attributes[typeof(ExtenderProvidedPropertyAttribute)] as ExtenderProvidedPropertyAttribute;
1894 IExtenderProvider prov = exAttr.Provider;
1899 IComponent component = prov as IComponent;
1901 if (component != null && component.Site != null)
1903 name = component.Site.Name;
1906 if (name == null || name.Length == 0)
1908 int ci = System.Threading.Interlocked.Increment(ref _collisionIndex) - 1;
1909 name = ci.ToString(CultureInfo.InvariantCulture);
1912 suffix = string.Format(CultureInfo.InvariantCulture, "_{0}", name);
1920 /// The name of the specified component, or null if the component has no name.
1921 /// In many cases this will return the same value as GetComponentName. If the
1922 /// component resides in a nested container or has other nested semantics, it may
1923 /// return a different fully qualfied name.
1925 public static string GetFullComponentName(object component) {
1926 if (component == null) throw new ArgumentNullException("component");
1927 return GetProvider(component).GetFullComponentName(component);
1930 private static Type GetNodeForBaseType(Type searchType)
1932 if (searchType.IsInterface)
1934 return InterfaceType;
1936 else if (searchType == InterfaceType)
1940 return searchType.BaseType;
1944 /// Gets a collection of properties for a specified type of component.
1946 public static PropertyDescriptorCollection GetProperties(Type componentType)
1948 if (componentType == null)
1950 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
1951 return new PropertyDescriptorCollection(null, true);
1954 return GetDescriptor(componentType, "componentType").GetProperties();
1958 /// Gets a collection of properties for a specified type of
1959 /// component using a specified array of attributes as a filter.
1961 public static PropertyDescriptorCollection GetProperties(Type componentType, Attribute[] attributes)
1963 if (componentType == null)
1965 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
1966 return new PropertyDescriptorCollection(null, true);
1969 PropertyDescriptorCollection properties = GetDescriptor(componentType, "componentType").GetProperties(attributes);
1971 if (attributes != null && attributes.Length > 0) {
1972 ArrayList filteredProperties = FilterMembers(properties, attributes);
1973 if (filteredProperties != null) {
1974 properties = new PropertyDescriptorCollection((PropertyDescriptor[])filteredProperties.ToArray(typeof(PropertyDescriptor)), true);
1978 DebugValidate(properties, componentType, attributes);
1983 /// Gets a collection of properties for a specified component.
1985 public static PropertyDescriptorCollection GetProperties(object component)
1987 return GetProperties(component, false);
1991 /// Gets a collection of properties for a specified component.
1993 [EditorBrowsable(EditorBrowsableState.Advanced)]
1994 public static PropertyDescriptorCollection GetProperties(object component, bool noCustomTypeDesc)
1996 return GetPropertiesImpl(component, null, noCustomTypeDesc, true);
2000 /// Gets a collection of properties for a specified
2001 /// component using a specified array of attributes
2004 public static PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes)
2006 return GetProperties(component, attributes, false);
2010 /// <para>Gets a collection of properties for a specified
2011 /// component using a specified array of attributes
2012 /// as a filter.</para>
2014 public static PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes, bool noCustomTypeDesc) {
2015 return GetPropertiesImpl(component, attributes, noCustomTypeDesc, false);
2019 /// Gets a collection of properties for a specified component. Uses the attribute filter
2020 /// only if noAttributes is false. This is to preserve backward compat for the case when
2021 /// no attribute filter was passed in (as against passing in null).
2023 private static PropertyDescriptorCollection GetPropertiesImpl(object component, Attribute[] attributes, bool noCustomTypeDesc, bool noAttributes) {
2024 if (component == null)
2026 Debug.Fail("COMPAT: Returning an empty collection, but you should not pass null here");
2027 return new PropertyDescriptorCollection(null, true);
2030 // We create a sort of pipeline for mucking with metadata. The pipeline
2031 // goes through the following process:
2033 // 1. Merge metadata from extenders.
2034 // 2. Allow services to filter the metadata
2035 // 3. If an attribute filter was specified, apply that.
2037 // The goal here is speed. We get speed by not copying or
2038 // allocating memory. We do this by allowing each phase of the
2039 // pipeline to cache its data in the object cache. If
2040 // a phase makes a change to the results, this change must cause
2041 // successive phases to recompute their results as well. "Results" is
2042 // always a collection, and the various stages of the pipeline may
2043 // replace or modify this collection (depending on if it's a
2044 // read-only IList or not). It is possible for the orignal
2045 // descriptor or attribute collection to pass through the entire
2046 // pipeline without modification.
2048 ICustomTypeDescriptor typeDesc = GetDescriptor(component, noCustomTypeDesc);
2049 ICollection results;
2051 // If we are handed a custom type descriptor we have several choices of action
2052 // we can take. If noCustomTypeDesc is true, it means that the custom type
2053 // descriptor is trying to find a baseline set of properties. In this case
2054 // we should merge in extended properties, but we do not let designers filter
2055 // because we're not done with the property set yet. If noCustomTypeDesc
2056 // is false, we don't do extender properties because the custom type descriptor
2057 // has already added them. In this case, we are doing a final pass so we
2058 // want to apply filtering. Finally, if the incoming object is not a custom
2059 // type descriptor, we do extenders and the filter.
2061 if (component is ICustomTypeDescriptor)
2063 results = noAttributes ? typeDesc.GetProperties() : typeDesc.GetProperties(attributes);
2064 if (noCustomTypeDesc)
2066 ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
2067 if (extDesc != null)
2069 ICollection extResults = noAttributes ? extDesc.GetProperties() : extDesc.GetProperties(attributes);
2070 results = PipelineMerge(PIPELINE_PROPERTIES, results, extResults, component, null);
2075 results = PipelineFilter(PIPELINE_PROPERTIES, results, component, null);
2076 results = PipelineAttributeFilter(PIPELINE_PROPERTIES, results, attributes, component, null);
2081 IDictionary cache = GetCache(component);
2082 results = noAttributes ? typeDesc.GetProperties() : typeDesc.GetProperties(attributes);
2083 results = PipelineInitialize(PIPELINE_PROPERTIES, results, cache);
2084 ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
2085 if (extDesc != null)
2087 ICollection extResults = noAttributes ? extDesc.GetProperties() : extDesc.GetProperties(attributes);
2088 results = PipelineMerge(PIPELINE_PROPERTIES, results, extResults, component, cache);
2091 results = PipelineFilter(PIPELINE_PROPERTIES, results, component, cache);
2092 results = PipelineAttributeFilter(PIPELINE_PROPERTIES, results, attributes, component, cache);
2095 PropertyDescriptorCollection props = results as PropertyDescriptorCollection;
2098 Trace("Properties : Allocated new property collection for {0}", component.GetType().Name);
2099 PropertyDescriptor[] propArray = new PropertyDescriptor[results.Count];
2100 results.CopyTo(propArray, 0);
2101 props = new PropertyDescriptorCollection(propArray, true);
2104 DebugValidate(props, component, attributes, noCustomTypeDesc);
2110 /// The GetProvider method returns a type description provider for
2111 /// the given object or type. This will always return a type description
2112 /// provider. Even the default TypeDescriptor implementation is built on
2113 /// a TypeDescriptionProvider, and this will be returned unless there is
2114 /// another provider that someone else has added.
2116 [EditorBrowsable(EditorBrowsableState.Advanced)]
2117 public static TypeDescriptionProvider GetProvider(Type type)
2121 throw new ArgumentNullException("type");
2124 return NodeFor(type, true);
2128 /// The GetProvider method returns a type description provider for
2129 /// the given object or type. This will always return a type description
2130 /// provider. Even the default TypeDescriptor implementation is built on
2131 /// a TypeDescriptionProvider, and this will be returned unless there is
2132 /// another provider that someone else has added.
2134 [EditorBrowsable(EditorBrowsableState.Advanced)]
2135 public static TypeDescriptionProvider GetProvider(object instance)
2137 if (instance == null)
2139 throw new ArgumentNullException("instance");
2142 return NodeFor(instance, true);
2146 /// This method returns a type description provider, but instead of creating
2147 /// a delegating provider for the type, this will walk all base types until
2148 /// it locates a provider. The provider returned cannot be cached. This
2149 /// method is used by the DelegatingTypeDescriptionProvider to efficiently
2150 /// locate the provider to delegate to.
2152 internal static TypeDescriptionProvider GetProviderRecursive(Type type) {
2153 return NodeFor(type, false);
2157 /// Returns an Type instance that can be used to perform reflection.
2159 [EditorBrowsable(EditorBrowsableState.Advanced)]
2160 public static Type GetReflectionType(Type type)
2164 throw new ArgumentNullException("type");
2167 return NodeFor(type).GetReflectionType(type);
2171 /// Returns an Type instance that can be used to perform reflection.
2173 [EditorBrowsable(EditorBrowsableState.Advanced)]
2174 public static Type GetReflectionType(object instance)
2176 if (instance == null)
2178 throw new ArgumentNullException("instance");
2181 return NodeFor(instance).GetReflectionType(instance);
2185 /// Retrieves the head type description node for a type.
2186 /// A head node pointing to a reflection based type description
2187 /// provider will be created on demand. This does not create
2188 /// a delegator, in which case the node returned may be
2189 /// a base type node.
2191 private static TypeDescriptionNode NodeFor(Type type) {
2192 return NodeFor(type, false);
2196 /// Retrieves the head type description node for a type.
2197 /// A head node pointing to a reflection based type description
2198 /// provider will be created on demand.
2200 /// If createDelegator is true, this method will create a delegation
2201 /// node for a type if the type has no node of its own. Delegation
2202 /// nodes should be created if you are going to hand this node
2203 /// out to a user. Without a delegation node, user code could
2204 /// skip providers that are added after their call. Delegation
2205 /// nodes solve that problem.
2207 /// If createDelegator is false, this method will recurse up the
2208 /// base type chain looking for nodes.
2210 private static TypeDescriptionNode NodeFor(Type type, bool createDelegator) {
2211 Debug.Assert(type != null, "Caller should validate");
2212 CheckDefaultProvider(type);
2214 // First, check our provider type table to see if we have a matching
2215 // provider for this type. The provider type table is a cache that
2216 // matches types to providers. When a new provider is added or
2217 // an existing one removed, the provider type table is torn
2218 // down and automatically rebuilt on demand.
2220 TypeDescriptionNode node = null;
2221 Type searchType = type;
2223 while (node == null) {
2224 node = (TypeDescriptionNode)_providerTypeTable[searchType];
2226 node = (TypeDescriptionNode)_providerTable[searchType];
2230 Type baseType = GetNodeForBaseType(searchType);
2232 if (searchType == typeof(object) || baseType == null) {
2234 lock (_providerTable) {
2235 node = (TypeDescriptionNode)_providerTable[searchType];
2238 // The reflect type description provider is a default provider that
2239 // can provide type information for all objects.
2240 node = new TypeDescriptionNode(new ReflectTypeDescriptionProvider());
2241 _providerTable[searchType] = node;
2242 Trace("Nodes : Allocated new type node. Now {0} nodes", _providerTable.Count);
2247 else if (createDelegator) {
2248 node = new TypeDescriptionNode(new DelegatingTypeDescriptionProvider(baseType));
2249 lock (_providerTable) {
2250 _providerTypeTable[searchType] = node;
2254 // Continue our search
2255 searchType = baseType;
2264 /// Retrieves the head type description node for an instance.
2265 /// Instance-based node lists are rare. If a node list is not
2266 /// available for a given instance, this will return the head node
2267 /// for the instance's type.
2269 private static TypeDescriptionNode NodeFor(object instance)
2271 return NodeFor(instance, false);
2275 /// Retrieves the head type description node for an instance.
2276 /// Instance-based node lists are rare. If a node list is not
2277 /// available for a given instance, this will return the head node
2278 /// for the instance's type. This variation offers a bool called
2279 /// createDelegator. If true and there is no node list for this
2280 /// instance, NodeFor will create a temporary "delegator node" that,
2281 /// when queried, will delegate to the type stored in the instance.
2282 /// This is done on demand, which means if someone else added a
2283 /// type description provider for the instance's type the delegator
2284 /// would pick up the new type. If a query is being made that does
2285 /// not involve publicly exposing the type description provider for
2286 /// the instance, the query should pass in fase (the default) for
2287 /// createDelegator because no object will be created.
2289 private static TypeDescriptionNode NodeFor(object instance, bool createDelegator)
2291 // For object instances, the provider cache key is not the object (that
2292 // would keep it in memory). Instead, it is a subclass of WeakReference
2293 // that overrides GetHashCode and Equals to make it appear to be the
2294 // object it is wrapping. A GC'd object causes WeakReference to return
2295 // false for all .Equals, but it always returns a valid hash code.
2297 Debug.Assert(instance != null, "Caller should validate");
2299 TypeDescriptionNode node = (TypeDescriptionNode)_providerTable[instance];
2302 Type type = instance.GetType();
2304 if (type.IsCOMObject)
2306 type = ComObjectType;
2309 if (createDelegator)
2311 node = new TypeDescriptionNode(new DelegatingTypeDescriptionProvider(type));
2312 Trace("Nodes : Allocated new instance node for {0}. Now {1} nodes", type.Name, _providerTable.Count);
2316 node = NodeFor(type);
2324 /// Simple linked list code to remove an element
2325 /// from the list. Returns the new head to the
2326 /// list. If the head points to an instance of
2327 /// DelegatingTypeDescriptionProvider, we clear the
2328 /// node because all it is doing is delegating elsewhere.
2330 /// Note that this behaves a little differently from normal
2331 /// linked list code. In a normal linked list, you remove
2332 /// then target node and fixup the links. In this linked
2333 /// list, we remove the node AFTER the target node, fixup
2334 /// the links, and fixup the underlying providers that each
2335 /// node references. The reason for this is that most
2336 /// providers keep a reference to the previous provider,
2337 /// which is exposed as one of these nodes. Therefore,
2338 /// to remove a provider the node following is most likely
2339 /// referenced by that provider
2341 private static void NodeRemove(object key, TypeDescriptionProvider provider)
2343 lock(_providerTable)
2345 TypeDescriptionNode head = (TypeDescriptionNode)_providerTable[key];
2346 TypeDescriptionNode target = head;
2347 TypeDescriptionNode prev = null;
2349 while(target != null && target.Provider != provider)
2352 target = target.Next;
2357 // We have our target node. There are three cases
2358 // to consider: the target is in the middle, the head,
2361 if (target.Next != null) {
2362 // If there is a node after the target node,
2363 // steal the node's provider and store it
2364 // at the target location. This removes
2365 // the provider at the target location without
2366 // the need to modify providers which may be
2367 // pointing to "target".
2368 target.Provider = target.Next.Provider;
2370 // Now remove target.Next from the list
2371 target.Next = target.Next.Next;
2373 // If the new provider we got is a delegating
2374 // provider, we can remove this node from
2375 // the list. The delegating provider should
2376 // always be at the end of the node list.
2377 if (target == head && target.Provider is DelegatingTypeDescriptionProvider) {
2378 Debug.Assert(target.Next == null, "Delegating provider should always be the last provider in the chain.");
2379 _providerTable.Remove(key);
2382 else if (target != head) {
2383 // If target is the last node, we can't
2384 // assign a new provider over to it. What
2385 // we can do, however, is assign a delegating
2386 // provider into the target node. This routes
2387 // requests from the previous provider into
2388 // the next base type provider list.
2390 // We don't do this if the target is the head.
2391 // In that case, we can remove the node
2392 // altogether since no one is pointing to it.
2394 Type keyType = key as Type;
2395 if (keyType == null) keyType = key.GetType();
2397 target.Provider = new DelegatingTypeDescriptionProvider(keyType.BaseType);
2400 _providerTable.Remove(key);
2403 // Finally, clear our cache of provider types; it might be invalid
2405 _providerTypeTable.Clear();
2411 /// This is the last stage in our filtering pipeline. Here, we apply any
2412 /// user-defined filter.
2414 private static ICollection PipelineAttributeFilter(int pipelineType, ICollection members, Attribute[] filter, object instance, IDictionary cache)
2416 Debug.Assert(pipelineType != PIPELINE_ATTRIBUTES, "PipelineAttributeFilter is not supported for attributes");
2418 IList list = members as ArrayList;
2420 if (filter == null || filter.Length == 0)
2425 // Now, check our cache. The cache state is only valid
2426 // if the data coming into us is read-only. If it is read-write,
2427 // that means something higher in the pipeline has already changed
2428 // it so we must recompute anyway.
2430 if (cache != null && (list == null || list.IsReadOnly))
2432 AttributeFilterCacheItem filterCache = cache[_pipelineAttributeFilterKeys[pipelineType]] as AttributeFilterCacheItem;
2433 if (filterCache != null && filterCache.IsValid(filter))
2435 return filterCache.FilteredMembers;
2439 // Our cache did not contain the correct state, so generate it.
2441 if (list == null || list.IsReadOnly)
2443 Trace("Pipeline : Filter needs to create member list for {0}", instance.GetType().Name);
2444 list = new ArrayList(members);
2447 ArrayList filterResult = FilterMembers(list, filter);
2448 if (filterResult != null) list = filterResult;
2450 // And, if we have a cache, store the updated state into it for future reference.
2454 ICollection cacheValue;
2456 switch(pipelineType)
2458 case PIPELINE_PROPERTIES:
2459 PropertyDescriptor[] propArray = new PropertyDescriptor[list.Count];
2460 list.CopyTo(propArray, 0);
2461 cacheValue = new PropertyDescriptorCollection(propArray, true);
2464 case PIPELINE_EVENTS:
2465 EventDescriptor[] eventArray = new EventDescriptor[list.Count];
2466 list.CopyTo(eventArray, 0);
2467 cacheValue = new EventDescriptorCollection(eventArray, true);
2471 Debug.Fail("unknown pipeline type");
2476 Trace("Pipeline : Attribute Filter results being cached for {0}", instance.GetType().Name);
2477 AttributeFilterCacheItem filterCache = new AttributeFilterCacheItem(filter, cacheValue);
2478 cache[_pipelineAttributeFilterKeys[pipelineType]] = filterCache;
2485 /// Metdata filtering is the third stage of our pipeline.
2486 /// In this stage we check to see if the given object is a
2487 /// sited component that provides the ITypeDescriptorFilterService
2488 /// object. If it does, we allow the TDS to filter the metadata.
2489 /// This will use the cache, if available, to store filtered
2492 private static ICollection PipelineFilter(int pipelineType, ICollection members, object instance, IDictionary cache)
2494 IComponent component = instance as IComponent;
2495 ITypeDescriptorFilterService componentFilter = null;
2497 if (component != null)
2499 ISite site = component.Site;
2502 componentFilter = site.GetService(typeof(ITypeDescriptorFilterService)) as ITypeDescriptorFilterService;
2506 // If we have no filter, there is nothing for us to do.
2508 IList list = members as ArrayList;
2510 if (componentFilter == null)
2512 Debug.Assert(cache == null || list == null || !cache.Contains(_pipelineFilterKeys[pipelineType]), "Earlier pipeline stage should have removed our cache");
2516 // Now, check our cache. The cache state is only valid
2517 // if the data coming into us is read-only. If it is read-write,
2518 // that means something higher in the pipeline has already changed
2519 // it so we must recompute anyway.
2521 if (cache != null && (list == null || list.IsReadOnly))
2523 FilterCacheItem cacheItem = cache[_pipelineFilterKeys[pipelineType]] as FilterCacheItem;
2524 if (cacheItem != null && cacheItem.IsValid(componentFilter)) {
2525 return cacheItem.FilteredMembers;
2529 // Cache either is dirty or doesn't exist. Re-filter the members.
2530 // We need to build an IDictionary of key->value pairs and invoke
2531 // Filter* on the filter service.
2533 OrderedDictionary filterTable = new OrderedDictionary(members.Count);
2536 switch(pipelineType)
2538 case PIPELINE_ATTRIBUTES:
2539 foreach(Attribute attr in members)
2541 filterTable[attr.TypeId] = attr;
2543 cacheResults = componentFilter.FilterAttributes(component, filterTable);
2546 case PIPELINE_PROPERTIES:
2547 case PIPELINE_EVENTS:
2548 foreach(MemberDescriptor desc in members)
2550 string descName = desc.Name;
2551 // We must handle the case of duplicate property names
2552 // because extender providers can provide any arbitrary
2553 // name. Our rule for this is simple: If we find a
2554 // duplicate name, resolve it back to the extender
2555 // provider that offered it and append "_" + the
2556 // provider name. If the provider has no name,
2557 // then append the object hash code.
2559 if (filterTable.Contains(descName))
2561 // First, handle the new property. Because
2562 // of the order in which we added extended
2563 // properties earlier in the pipeline, we can be
2564 // sure that the new property is an extender. We
2565 // cannot be sure that the existing property
2566 // in the table is an extender, so we will
2569 string suffix = GetExtenderCollisionSuffix(desc);
2570 Debug.Assert(suffix != null, "Name collision with non-extender property.");
2573 filterTable[descName + suffix] = desc;
2576 // Now, handle the original property.
2578 MemberDescriptor origDesc = (MemberDescriptor)filterTable[descName];
2579 suffix = GetExtenderCollisionSuffix(origDesc);
2582 filterTable.Remove(descName);
2583 filterTable[origDesc.Name + suffix] = origDesc;
2588 filterTable[descName] = desc;
2591 if (pipelineType == PIPELINE_PROPERTIES)
2593 cacheResults = componentFilter.FilterProperties(component, filterTable);
2597 cacheResults = componentFilter.FilterEvents(component, filterTable);
2602 Debug.Fail("unknown pipeline type");
2603 cacheResults = false;
2607 // See if we can re-use the IList were were passed. If we can,
2608 // it is more efficient to re-use its slots than to generate new ones.
2610 if (list == null || list.IsReadOnly)
2612 Trace("Pipeline : Filter needs to create member list for {0}", instance.GetType().Name);
2613 list = new ArrayList(filterTable.Values);
2618 foreach(object obj in filterTable.Values)
2624 // Component filter has requested that we cache these
2625 // new changes. We store them as a correctly typed collection
2626 // so on successive invocations we can simply return. Note that
2627 // we always return the IList so that successive stages in the
2628 // pipeline can modify it.
2630 if (cacheResults && cache != null)
2632 ICollection cacheValue;
2634 switch(pipelineType)
2636 case PIPELINE_ATTRIBUTES:
2637 Attribute[] attrArray = new Attribute[list.Count];
2640 list.CopyTo(attrArray, 0);
2642 catch(InvalidCastException)
2644 throw new ArgumentException(SR.GetString(SR.TypeDescriptorExpectedElementType, typeof(Attribute).FullName));
2646 cacheValue = new AttributeCollection(attrArray);
2649 case PIPELINE_PROPERTIES:
2650 PropertyDescriptor[] propArray = new PropertyDescriptor[list.Count];
2653 list.CopyTo(propArray, 0);
2655 catch(InvalidCastException)
2657 throw new ArgumentException(SR.GetString(SR.TypeDescriptorExpectedElementType, typeof(PropertyDescriptor).FullName));
2659 cacheValue = new PropertyDescriptorCollection(propArray, true);
2662 case PIPELINE_EVENTS:
2663 EventDescriptor[] eventArray = new EventDescriptor[list.Count];
2666 list.CopyTo(eventArray, 0);
2668 catch(InvalidCastException)
2670 throw new ArgumentException(SR.GetString(SR.TypeDescriptorExpectedElementType, typeof(EventDescriptor).FullName));
2672 cacheValue = new EventDescriptorCollection(eventArray, true);
2676 Debug.Fail("unknown pipeline type");
2681 Trace("Pipeline : Filter results being cached for {0}", instance.GetType().Name);
2683 FilterCacheItem cacheItem = new FilterCacheItem(componentFilter, cacheValue);
2684 cache[_pipelineFilterKeys[pipelineType]] = cacheItem;
2685 cache.Remove(_pipelineAttributeFilterKeys[pipelineType]);
2692 /// This is the first stage in the pipeline. This checks the incoming member collection and if it
2693 /// differs from what we have seen in the past, it invalidates all successive pipelines.
2695 private static ICollection PipelineInitialize (int pipelineType, ICollection members, IDictionary cache) {
2696 if (cache != null) {
2698 bool cacheValid = true;
2700 ICollection cachedMembers = cache[_pipelineInitializeKeys[pipelineType]] as ICollection;
2701 if (cachedMembers != null && cachedMembers.Count == members.Count) {
2702 IEnumerator cacheEnum = cachedMembers.GetEnumerator();
2703 IEnumerator memberEnum = members.GetEnumerator();
2705 while(cacheEnum.MoveNext() && memberEnum.MoveNext()) {
2706 if (cacheEnum.Current != memberEnum.Current) {
2714 // The cache wasn't valid. Remove all subsequent cache layers
2715 // and then save off new data.
2716 cache.Remove(_pipelineMergeKeys[pipelineType]);
2717 cache.Remove(_pipelineFilterKeys[pipelineType]);
2718 cache.Remove(_pipelineAttributeFilterKeys[pipelineType]);
2719 cache[_pipelineInitializeKeys[pipelineType]] = members;
2727 /// Metadata merging is the second stage of our metadata pipeline. This stage
2728 /// merges extended metdata with primary metadata, and stores it in
2729 /// the cache if it is available.
2731 private static ICollection PipelineMerge(int pipelineType, ICollection primary, ICollection secondary, object instance, IDictionary cache)
2733 // If there is no secondary collection, there is nothing to merge.
2735 if (secondary == null || secondary.Count == 0)
2740 // Next, if we were given a cache, see if it has accurate data.
2744 ICollection mergeCache = cache[_pipelineMergeKeys[pipelineType]] as ICollection;
2745 if (mergeCache != null && mergeCache.Count == (primary.Count + secondary.Count))
2747 // Walk the merge cache.
2748 IEnumerator mergeEnum = mergeCache.GetEnumerator();
2749 IEnumerator primaryEnum = primary.GetEnumerator();
2752 while(primaryEnum.MoveNext() && mergeEnum.MoveNext())
2754 if (primaryEnum.Current != mergeEnum.Current)
2763 IEnumerator secondaryEnum = secondary.GetEnumerator();
2765 while(secondaryEnum.MoveNext() && mergeEnum.MoveNext())
2767 if (secondaryEnum.Current != mergeEnum.Current)
2782 // Our cache didn't match. We need to merge metadata and return
2783 // the merged copy. We create an array list here, rather than
2784 // an array, because we want successive sections of the
2785 // pipeline to be able to modify it.
2787 ArrayList list = new ArrayList(primary.Count + secondary.Count);
2788 foreach(object obj in primary)
2792 foreach(object obj in secondary)
2799 ICollection cacheValue;
2801 switch(pipelineType)
2803 case PIPELINE_ATTRIBUTES:
2804 Attribute[] attrArray = new Attribute[list.Count];
2805 list.CopyTo(attrArray, 0);
2806 cacheValue = new AttributeCollection(attrArray);
2809 case PIPELINE_PROPERTIES:
2810 PropertyDescriptor[] propArray = new PropertyDescriptor[list.Count];
2811 list.CopyTo(propArray, 0);
2812 cacheValue = new PropertyDescriptorCollection(propArray, true);
2815 case PIPELINE_EVENTS:
2816 EventDescriptor[] eventArray = new EventDescriptor[list.Count];
2817 list.CopyTo(eventArray, 0);
2818 cacheValue = new EventDescriptorCollection(eventArray, true);
2822 Debug.Fail("unknown pipeline type");
2827 Trace("Pipeline : Merge results being cached for {0}", instance.GetType().Name);
2828 cache[_pipelineMergeKeys[pipelineType]] = cacheValue;
2829 cache.Remove(_pipelineFilterKeys[pipelineType]);
2830 cache.Remove(_pipelineAttributeFilterKeys[pipelineType]);
2836 private static void RaiseRefresh(object component) {
2837 // This volatility prevents the JIT from making certain optimizations
2838 // that could cause this firing pattern to break. Although the likelihood
2839 // the JIT makes those changes is mostly theoretical
2840 RefreshEventHandler handler = Volatile.Read(ref Refreshed);
2842 if (handler != null)
2844 handler(new RefreshEventArgs(component));
2848 private static void RaiseRefresh(Type type) {
2849 RefreshEventHandler handler = Volatile.Read(ref Refreshed);
2851 if (handler != null)
2853 handler(new RefreshEventArgs(type));
2858 /// Clears the properties and events for the specified
2859 /// component from the cache.
2861 public static void Refresh(object component)
2863 Refresh(component, true);
2866 private static void Refresh(object component, bool refreshReflectionProvider) {
2868 DebugTypeDescriptor.Refresh(component);
2871 if (component == null)
2873 Debug.Fail("COMPAT: Returning, but you should not pass null here");
2877 // Build up a list of type description providers for
2878 // each type that is a derived type of the given
2879 // object. We will invalidate the metadata at
2880 // each of these levels.
2883 if (refreshReflectionProvider)
2885 Type type = component.GetType();
2887 lock (_providerTable)
2889 // ReflectTypeDescritionProvider is only bound to object, but we
2890 // need go to through the entire table to try to find custom
2891 // providers. If we find one, will clear our cache.
2892 foreach (DictionaryEntry de in _providerTable)
2894 Type nodeType = de.Key as Type;
2895 if (nodeType != null && type.IsAssignableFrom(nodeType) || nodeType == typeof(object))
2897 TypeDescriptionNode node = (TypeDescriptionNode)de.Value;
2898 while (node != null && !(node.Provider is ReflectTypeDescriptionProvider))
2906 ReflectTypeDescriptionProvider provider = (ReflectTypeDescriptionProvider)node.Provider;
2907 if (provider.IsPopulated(type))
2910 provider.Refresh(type);
2918 // We need to clear our filter even if no typedescriptionprovider had data.
2919 // This is because if you call Refresh(instance1) and Refresh(instance2)
2920 // and instance1 and instance2 are of the same type, you will end up not
2921 // actually deleting the dictionary cache on instance2 if you skip this
2922 // when you don't find a typedescriptionprovider.
2923 // However, we do not need to fire the event if we did not find any loaded
2924 // typedescriptionprovider AND the cache is empty (if someone repeatedly calls
2925 // Refresh on an instance).
2927 // Now, clear any cached data for the instance.
2929 IDictionary cache = GetCache(component);
2930 if (found || cache!= null)
2934 Trace("Pipeline : Refresh clearing all pipeline caches");
2935 for (int idx = 0; idx < _pipelineFilterKeys.Length; idx++)
2937 cache.Remove(_pipelineFilterKeys[idx]);
2938 cache.Remove(_pipelineMergeKeys[idx]);
2939 cache.Remove(_pipelineAttributeFilterKeys[idx]);
2944 Interlocked.Increment(ref _metadataVersion);
2946 // And raise the event.
2948 RaiseRefresh(component);
2953 /// Clears the properties and events for the specified type
2954 /// of component from the cache.
2956 public static void Refresh(Type type)
2959 DebugTypeDescriptor.Refresh(type);
2964 Debug.Fail("COMPAT: Returning, but you should not pass null here");
2968 // Build up a list of type description providers for
2969 // each type that is a derived type of the given
2970 // type. We will invalidate the metadata at
2971 // each of these levels.
2975 lock(_providerTable)
2977 // ReflectTypeDescritionProvider is only bound to object, but we
2978 // need go to through the entire table to try to find custom
2979 // providers. If we find one, will clear our cache.
2980 foreach(DictionaryEntry de in _providerTable)
2982 Type nodeType = de.Key as Type;
2983 if (nodeType != null && type.IsAssignableFrom(nodeType) || nodeType == typeof(object))
2985 TypeDescriptionNode node = (TypeDescriptionNode)de.Value;
2986 while(node != null && !(node.Provider is ReflectTypeDescriptionProvider))
2994 ReflectTypeDescriptionProvider provider = (ReflectTypeDescriptionProvider)node.Provider;
2995 if (provider.IsPopulated(type))
2998 provider.Refresh(type);
3005 // We only clear our filter and fire the refresh event if there was one or
3006 // more type description providers that were populated with metdata.
3007 // This prevents us from doing a lot of extra work and raising
3008 // a ton more events than we need to.
3012 Interlocked.Increment(ref _metadataVersion);
3014 // And raise the event.
3021 /// Clears the properties and events for the specified
3022 /// module from the cache.
3024 public static void Refresh(Module module)
3027 DebugTypeDescriptor.Refresh(module);
3032 Debug.Fail("COMPAT: Returning, but you should not pass null here");
3036 // Build up a list of type description providers for
3037 // each type that is a derived type of the given
3038 // object. We will invalidate the metadata at
3039 // each of these levels.
3040 Hashtable refreshedTypes = null;
3042 lock(_providerTable)
3044 foreach(DictionaryEntry de in _providerTable)
3046 Type nodeType = de.Key as Type;
3047 if (nodeType != null && nodeType.Module.Equals(module) || nodeType == typeof(object))
3049 TypeDescriptionNode node = (TypeDescriptionNode)de.Value;
3050 while(node != null && !(node.Provider is ReflectTypeDescriptionProvider))
3052 if (refreshedTypes == null) {
3053 refreshedTypes = new Hashtable();
3055 refreshedTypes[nodeType] = nodeType;
3061 ReflectTypeDescriptionProvider provider = (ReflectTypeDescriptionProvider)node.Provider;
3062 Type[] populatedTypes = provider.GetPopulatedTypes(module);
3064 foreach(Type populatedType in populatedTypes) {
3065 provider.Refresh(populatedType);
3066 if (refreshedTypes == null) {
3067 refreshedTypes = new Hashtable();
3069 refreshedTypes[populatedType] = populatedType;
3076 // And raise the event if types were refresh and handlers are attached.
3078 if (refreshedTypes != null && Refreshed != null)
3080 foreach(Type t in refreshedTypes.Keys) {
3087 /// Clears the properties and events for the specified
3088 /// assembly from the cache.
3090 [ResourceExposure(ResourceScope.None)]
3091 [ResourceConsumption(ResourceScope.Machine | ResourceScope.Assembly, ResourceScope.Machine | ResourceScope.Assembly)]
3092 public static void Refresh(Assembly assembly)
3094 if (assembly == null)
3096 Debug.Fail("COMPAT: Returning, but you should not pass null here");
3100 foreach (Module mod in assembly.GetModules())
3105 // Debug type descriptor has the same code, so our call above will handle this.
3109 /// The RemoveAssociation method removes an association with an object.
3111 [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
3112 [EditorBrowsable(EditorBrowsableState.Advanced)]
3113 public static void RemoveAssociation(object primary, object secondary)
3115 if (primary == null)
3117 throw new ArgumentNullException("primary");
3120 if (secondary == null)
3122 throw new ArgumentNullException("secondary");
3125 Hashtable assocTable = _associationTable;
3126 if (assocTable != null)
3128 IList associations = (IList)assocTable[primary];
3129 if (associations != null)
3133 for (int idx = associations.Count - 1; idx >= 0; idx--)
3135 // Look for an associated object that has a type that
3136 // matches the given type.
3138 WeakReference weakRef = (WeakReference)associations[idx];
3139 object secondaryItem = weakRef.Target;
3140 if (secondaryItem == null || secondaryItem == secondary)
3142 associations.RemoveAt(idx);
3151 /// The RemoveAssociations method removes all associations for a primary object.
3153 [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
3154 [EditorBrowsable(EditorBrowsableState.Advanced)]
3155 public static void RemoveAssociations(object primary)
3157 if (primary == null)
3159 throw new ArgumentNullException("primary");
3162 Hashtable assocTable = _associationTable;
3163 if (assocTable != null)
3165 assocTable.Remove(primary);
3170 /// The RemoveProvider method removes a previously added type
3171 /// description provider. Removing a provider causes a Refresh
3172 /// event to be raised for the object or type the provider is
3173 /// associated with.
3175 [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
3176 [EditorBrowsable(EditorBrowsableState.Advanced)]
3177 public static void RemoveProvider(TypeDescriptionProvider provider, Type type)
3179 if (provider == null)
3181 throw new ArgumentNullException("provider");
3186 throw new ArgumentNullException("type");
3189 // Walk the nodes until we find the right one, and then remove it.
3190 NodeRemove(type, provider);
3195 /// The RemoveProvider method removes a previously added type
3196 /// description provider. Removing a provider causes a Refresh
3197 /// event to be raised for the object or type the provider is
3198 /// associated with.
3200 [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
3201 [EditorBrowsable(EditorBrowsableState.Advanced)]
3202 public static void RemoveProvider(TypeDescriptionProvider provider, object instance)
3204 if (provider == null)
3206 throw new ArgumentNullException("provider");
3209 if (instance == null)
3211 throw new ArgumentNullException("instance");
3214 // Walk the nodes until we find the right one, and then remove it.
3215 NodeRemove(instance, provider);
3216 RaiseRefresh(instance);
3221 /// The RemoveProvider method removes a previously added type
3222 /// description provider. Removing a provider causes a Refresh
3223 /// event to be raised for the object or type the provider is
3224 /// associated with.
3226 /// This method can be called from partially trusted code. If
3227 /// <see cref="TypeDescriptorPermissionFlags.RestrictedRegistrationAccess"/>
3228 /// is defined, the caller can unregister a provider for the specified type
3229 /// if it's also partially trusted.
3231 [EditorBrowsable(EditorBrowsableState.Advanced)]
3232 public static void RemoveProviderTransparent(TypeDescriptionProvider provider, Type type)
3234 if (provider == null)
3236 throw new ArgumentNullException("provider");
3241 throw new ArgumentNullException("type");
3244 PermissionSet typeDescriptorPermission = new PermissionSet(PermissionState.None);
3245 typeDescriptorPermission.AddPermission(new TypeDescriptorPermission(TypeDescriptorPermissionFlags.RestrictedRegistrationAccess));
3247 PermissionSet targetPermissions = type.Assembly.PermissionSet;
3248 targetPermissions = targetPermissions.Union(typeDescriptorPermission);
3250 targetPermissions.Demand();
3252 RemoveProvider(provider, type);
3256 /// The RemoveProvider method removes a previously added type
3257 /// description provider. Removing a provider causes a Refresh
3258 /// event to be raised for the object or type the provider is
3259 /// associated with.
3261 /// This method can be called from partially trusted code. If
3262 /// <see cref="TypeDescriptorPermissionFlags.RestrictedRegistrationAccess"/>
3263 /// is defined, the caller can register a provider for the specified instance
3264 /// if its type is also partially trusted.
3266 [EditorBrowsable(EditorBrowsableState.Advanced)]
3267 public static void RemoveProviderTransparent(TypeDescriptionProvider provider, object instance)
3269 if (provider == null)
3271 throw new ArgumentNullException("provider");
3274 if (instance == null)
3276 throw new ArgumentNullException("instance");
3279 Type type = instance.GetType();
3281 PermissionSet typeDescriptorPermission = new PermissionSet(PermissionState.None);
3282 typeDescriptorPermission.AddPermission(new TypeDescriptorPermission(TypeDescriptorPermissionFlags.RestrictedRegistrationAccess));
3284 PermissionSet targetPermissions = type.Assembly.PermissionSet;
3285 targetPermissions = targetPermissions.Union(typeDescriptorPermission);
3287 targetPermissions.Demand();
3289 RemoveProvider(provider, instance);
3293 /// This function takes a member descriptor and an attribute and determines whether
3294 /// the member satisfies the particular attribute. This either means that the member
3295 /// contains the attribute or the member does not contain the attribute and the default
3296 /// for the attribute matches the passed in attribute.
3298 private static bool ShouldHideMember(MemberDescriptor member, Attribute attribute)
3300 if (member == null || attribute == null)
3305 Attribute memberAttribute = member.Attributes[attribute.GetType()];
3306 if (memberAttribute == null)
3308 return !attribute.IsDefaultAttribute();
3312 return !(attribute.Match(memberAttribute));
3317 /// Sorts descriptors by name of the descriptor.
3319 public static void SortDescriptorArray(IList infos)
3323 throw new ArgumentNullException("infos");
3326 ArrayList.Adapter(infos).Sort(MemberDescriptorComparer.Instance);
3330 /// Internal tracing API for debugging type descriptor.
3332 [Conditional("DEBUG")]
3333 internal static void Trace(string message, params object[] args)
3335 Debug.WriteLineIf(TraceDescriptor.Enabled, string.Format(CultureInfo.InvariantCulture, "TypeDescriptor : {0}", string.Format(CultureInfo.InvariantCulture, message, args)));
3339 /// This is a type description provider that adds the given
3340 /// array of attributes to a class or instance, preserving the rest
3341 /// of the metadata in the process.
3343 private sealed class AttributeProvider : TypeDescriptionProvider
3348 /// Creates a new attribute provider.
3350 internal AttributeProvider(TypeDescriptionProvider existingProvider, params Attribute[] attrs) : base(existingProvider)
3356 /// Creates a custom type descriptor that replaces the attributes.
3358 public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
3360 return new AttributeTypeDescriptor(_attrs, base.GetTypeDescriptor(objectType, instance));
3364 /// Our custom type descriptor.
3366 private class AttributeTypeDescriptor : CustomTypeDescriptor
3368 Attribute[] _attributeArray;
3371 /// Creates a new custom type descriptor that can merge
3372 /// the provided set of attributes with the existing set.
3374 internal AttributeTypeDescriptor(Attribute[] attrs, ICustomTypeDescriptor parent) : base(parent)
3376 _attributeArray = attrs;
3380 /// Retrieves the merged set of attributes. We do not cache
3381 /// this because there is always the possibility that someone
3382 /// changed our parent provider's metadata. TypeDescriptor
3383 /// will cache this for us anyhow.
3385 public override AttributeCollection GetAttributes()
3387 Attribute[] finalAttr = null;
3388 AttributeCollection existing = base.GetAttributes();
3389 Attribute[] newAttrs = _attributeArray;
3390 Attribute[] newArray = new Attribute[existing.Count + newAttrs.Length];
3391 int actualCount = existing.Count;
3392 existing.CopyTo(newArray, 0);
3394 for (int idx = 0; idx < newAttrs.Length; idx++)
3397 Debug.Assert(newAttrs[idx] != null, "_attributes contains a null member");
3399 // We must see if this attribute is already in the existing
3400 // array. If it is, we replace it.
3402 for (int existingIdx = 0; existingIdx < existing.Count; existingIdx++)
3404 if (newArray[existingIdx].TypeId.Equals(newAttrs[idx].TypeId))
3407 newArray[existingIdx] = newAttrs[idx];
3414 newArray[actualCount++] = newAttrs[idx];
3418 // Now, if we collapsed some attributes, create a new array.
3420 if (actualCount < newArray.Length)
3422 finalAttr = new Attribute[actualCount];
3423 Array.Copy(newArray, 0, finalAttr, 0, actualCount);
3427 finalAttr= newArray;
3430 return new AttributeCollection(finalAttr);
3436 /// This class is a type description provider that works with the IComNativeDescriptorHandler
3439 private sealed class ComNativeDescriptionProvider : TypeDescriptionProvider
3441 #pragma warning disable 618
3442 private IComNativeDescriptorHandler _handler;
3444 internal ComNativeDescriptionProvider(IComNativeDescriptorHandler handler)
3450 /// Returns the COM handler object.
3452 internal IComNativeDescriptorHandler Handler
3463 #pragma warning restore 618
3466 /// Implements GetTypeDescriptor. This creates a custom type
3467 /// descriptor that walks the linked list for each of its calls.
3470 [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters")]
3471 public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
3473 if (objectType == null)
3475 throw new ArgumentNullException("objectType");
3478 if (instance == null)
3483 if (!objectType.IsInstanceOfType(instance))
3485 throw new ArgumentException("instance");
3488 return new ComNativeTypeDescriptor(_handler, instance);
3492 /// This type descriptor sits on top of a native
3493 /// descriptor handler.
3495 private sealed class ComNativeTypeDescriptor : ICustomTypeDescriptor
3497 #pragma warning disable 618
3498 private IComNativeDescriptorHandler _handler;
3499 private object _instance;
3502 /// Creates a new ComNativeTypeDescriptor.
3504 internal ComNativeTypeDescriptor(IComNativeDescriptorHandler handler, object instance)
3507 _instance = instance;
3509 #pragma warning restore 618
3512 /// ICustomTypeDescriptor implementation.
3514 AttributeCollection ICustomTypeDescriptor.GetAttributes()
3516 return _handler.GetAttributes(_instance);
3520 /// ICustomTypeDescriptor implementation.
3522 string ICustomTypeDescriptor.GetClassName()
3524 return _handler.GetClassName(_instance);
3528 /// ICustomTypeDescriptor implementation.
3530 string ICustomTypeDescriptor.GetComponentName()
3536 /// ICustomTypeDescriptor implementation.
3538 TypeConverter ICustomTypeDescriptor.GetConverter()
3540 return _handler.GetConverter(_instance);
3544 /// ICustomTypeDescriptor implementation.
3546 EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
3548 return _handler.GetDefaultEvent(_instance);
3552 /// ICustomTypeDescriptor implementation.
3554 PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
3556 return _handler.GetDefaultProperty(_instance);
3560 /// ICustomTypeDescriptor implementation.
3562 object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
3564 return _handler.GetEditor(_instance, editorBaseType);
3568 /// ICustomTypeDescriptor implementation.
3570 EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
3572 return _handler.GetEvents(_instance);
3576 /// ICustomTypeDescriptor implementation.
3578 EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
3580 return _handler.GetEvents(_instance, attributes);
3584 /// ICustomTypeDescriptor implementation.
3586 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
3588 return _handler.GetProperties(_instance, null);
3592 /// ICustomTypeDescriptor implementation.
3594 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
3596 return _handler.GetProperties(_instance, attributes);
3600 /// ICustomTypeDescriptor implementation.
3602 object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
3610 /// This is a simple class that is used to store a filtered
3611 /// set of members in an object's dictionary cache. It is
3612 /// used by the PipelineAttributeFilter method.
3614 private sealed class AttributeFilterCacheItem
3616 private Attribute[] _filter;
3617 internal ICollection FilteredMembers;
3619 internal AttributeFilterCacheItem(Attribute[] filter, ICollection filteredMembers)
3622 FilteredMembers = filteredMembers;
3625 internal bool IsValid(Attribute[] filter)
3627 if (_filter.Length != filter.Length) return false;
3629 for (int idx = 0; idx < filter.Length; idx++) {
3630 if (_filter[idx] != filter[idx]) {
3640 /// This small class contains cache information for the filter stage of our
3641 /// caching algorithm. It is used by the PipelineFilter method.
3643 private sealed class FilterCacheItem {
3644 private ITypeDescriptorFilterService _filterService;
3645 internal ICollection FilteredMembers;
3647 internal FilterCacheItem(ITypeDescriptorFilterService filterService, ICollection filteredMembers) {
3648 _filterService = filterService;
3649 FilteredMembers = filteredMembers;
3652 internal bool IsValid(ITypeDescriptorFilterService filterService) {
3653 if (!Object.ReferenceEquals(_filterService, filterService)) return false;
3659 /// An unimplemented interface. What is this? It is an interface that nobody ever
3660 /// implements, of course? Where and why would it be used? Why, to find cross-process
3661 /// remoted objects, of course! If a well-known object comes in from a cross process
3662 /// connection, the remoting layer does contain enough type information to determine
3663 /// if an object implements an interface. It assumes that if you are going to cast
3664 /// an object to an interface that you know what you're doing, and allows the cast,
3665 /// even for objects that DON'T actually implement the interface. The error here
3666 /// is raised later when you make your first call on that interface pointer: you
3667 /// get a remoting exception.
3669 /// This is a big problem for code that does "is" and "as" checks to detect the
3670 /// presence of an interface. We do that all over the place here, so we do a check
3671 /// during parameter validation to see if an object implements IUnimplemented. If it
3672 /// does, we know that what we really have is a lying remoting proxy, and we bail.
3674 private interface IUnimplemented {}
3677 /// This comparer compares member descriptors for sorting.
3679 private sealed class MemberDescriptorComparer : IComparer {
3680 public static readonly MemberDescriptorComparer Instance = new MemberDescriptorComparer();
3682 public int Compare(object left, object right) {
3683 return string.Compare(((MemberDescriptor)left).Name, ((MemberDescriptor)right).Name, false, CultureInfo.InvariantCulture);
3688 /// This is a merged type descriptor that can merge the output of
3689 /// a primary and secondary type descriptor. If the primary doesn't
3690 /// provide the needed information, the request is passed on to the
3693 private sealed class MergedTypeDescriptor : ICustomTypeDescriptor
3695 private ICustomTypeDescriptor _primary;
3696 private ICustomTypeDescriptor _secondary;
3699 /// Creates a new MergedTypeDescriptor.
3701 internal MergedTypeDescriptor(ICustomTypeDescriptor primary, ICustomTypeDescriptor secondary)
3704 _secondary = secondary;
3708 /// ICustomTypeDescriptor implementation.
3710 AttributeCollection ICustomTypeDescriptor.GetAttributes()
3712 AttributeCollection attrs = _primary.GetAttributes();
3715 attrs = _secondary.GetAttributes();
3718 Debug.Assert(attrs != null, "Someone should have handled this");
3723 /// ICustomTypeDescriptor implementation.
3725 string ICustomTypeDescriptor.GetClassName()
3727 string className = _primary.GetClassName();
3728 if (className == null)
3730 className = _secondary.GetClassName();
3733 Debug.Assert(className != null, "Someone should have handled this");
3738 /// ICustomTypeDescriptor implementation.
3740 string ICustomTypeDescriptor.GetComponentName()
3742 string name = _primary.GetComponentName();
3745 name = _secondary.GetComponentName();
3752 /// ICustomTypeDescriptor implementation.
3754 TypeConverter ICustomTypeDescriptor.GetConverter()
3756 TypeConverter converter = _primary.GetConverter();
3757 if (converter == null)
3759 converter = _secondary.GetConverter();
3762 Debug.Assert(converter != null, "Someone should have handled this");
3767 /// ICustomTypeDescriptor implementation.
3769 EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
3771 EventDescriptor evt = _primary.GetDefaultEvent();
3774 evt = _secondary.GetDefaultEvent();
3781 /// ICustomTypeDescriptor implementation.
3783 PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
3785 PropertyDescriptor prop = _primary.GetDefaultProperty();
3788 prop = _secondary.GetDefaultProperty();
3795 /// ICustomTypeDescriptor implementation.
3797 object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
3799 if (editorBaseType == null)
3801 throw new ArgumentNullException("editorBaseType");
3804 object editor = _primary.GetEditor(editorBaseType);
3807 editor = _secondary.GetEditor(editorBaseType);
3814 /// ICustomTypeDescriptor implementation.
3816 EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
3818 EventDescriptorCollection events = _primary.GetEvents();
3821 events = _secondary.GetEvents();
3824 Debug.Assert(events != null, "Someone should have handled this");
3829 /// ICustomTypeDescriptor implementation.
3831 EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
3833 EventDescriptorCollection events = _primary.GetEvents(attributes);
3836 events = _secondary.GetEvents(attributes);
3839 Debug.Assert(events != null, "Someone should have handled this");
3844 /// ICustomTypeDescriptor implementation.
3846 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
3848 PropertyDescriptorCollection properties = _primary.GetProperties();
3849 if (properties == null)
3851 properties = _secondary.GetProperties();
3854 Debug.Assert(properties != null, "Someone should have handled this");
3859 /// ICustomTypeDescriptor implementation.
3861 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
3863 PropertyDescriptorCollection properties = _primary.GetProperties(attributes);
3864 if (properties == null)
3866 properties = _secondary.GetProperties(attributes);
3869 Debug.Assert(properties != null, "Someone should have handled this");
3874 /// ICustomTypeDescriptor implementation.
3876 object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
3878 object owner = _primary.GetPropertyOwner(pd);
3881 owner = _secondary.GetPropertyOwner(pd);
3889 /// This is a linked list node that is comprised of a type
3890 /// description provider. Each node contains a Next pointer
3891 /// to the next node in the list and also a Provider pointer
3892 /// which contains the type description provider this node
3893 /// represents. The implementation of TypeDescriptionProvider
3894 /// that the node provides simply invokes the corresponding
3895 /// method on the node's provider.
3897 private sealed class TypeDescriptionNode : TypeDescriptionProvider
3899 internal TypeDescriptionNode Next;
3900 internal TypeDescriptionProvider Provider;
3903 /// Creates a new type description node.
3905 internal TypeDescriptionNode(TypeDescriptionProvider provider)
3907 Provider = provider;
3911 /// Implements CreateInstance. This just walks the linked list
3912 /// looking for someone who implements the call.
3914 public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)
3916 if (objectType == null)
3918 throw new ArgumentNullException("objectType");
3921 if (argTypes != null)
3925 throw new ArgumentNullException("args");
3928 if (argTypes.Length != args.Length)
3930 throw new ArgumentException(SR.GetString(SR.TypeDescriptorArgsCountMismatch));
3934 return Provider.CreateInstance(provider, objectType, argTypes, args);
3938 /// Implements GetCache. This just walks the linked
3939 /// list looking for someone who implements the call.
3941 public override IDictionary GetCache(object instance)
3943 if (instance == null)
3945 throw new ArgumentNullException("instance");
3948 return Provider.GetCache(instance);
3952 /// Implements GetExtendedTypeDescriptor. This creates a custom type
3953 /// descriptor that walks the linked list for each of its calls.
3955 public override ICustomTypeDescriptor GetExtendedTypeDescriptor(object instance)
3957 if (instance == null)
3959 throw new ArgumentNullException("instance");
3962 return new DefaultExtendedTypeDescriptor(this, instance);
3965 protected internal override IExtenderProvider[] GetExtenderProviders(object instance)
3967 if (instance == null)
3969 throw new ArgumentNullException("instance");
3972 return Provider.GetExtenderProviders(instance);
3976 /// The name of the specified component, or null if the component has no name.
3977 /// In many cases this will return the same value as GetComponentName. If the
3978 /// component resides in a nested container or has other nested semantics, it may
3979 /// return a different fully qualfied name.
3981 /// If not overridden, the default implementation of this method will call
3982 /// GetTypeDescriptor.GetComponentName.
3984 public override string GetFullComponentName(object component)
3986 if (component == null)
3988 throw new ArgumentNullException("component");
3991 return Provider.GetFullComponentName(component);
3995 /// Implements GetReflectionType. This just walks the linked list
3996 /// looking for someone who implements the call.
3998 public override Type GetReflectionType(Type objectType, object instance)
4000 if (objectType == null)
4002 throw new ArgumentNullException("objectType");
4005 return Provider.GetReflectionType(objectType, instance);
4008 public override Type GetRuntimeType(Type objectType)
4010 if (objectType == null)
4012 throw new ArgumentNullException("objectType");
4015 return Provider.GetRuntimeType(objectType);
4019 /// Implements GetTypeDescriptor. This creates a custom type
4020 /// descriptor that walks the linked list for each of its calls.
4023 [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters")]
4024 public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
4026 if (objectType == null)
4028 throw new ArgumentNullException("objectType");
4031 if (instance != null && !objectType.IsInstanceOfType(instance))
4033 throw new ArgumentException("instance");
4036 return new DefaultTypeDescriptor(this, objectType, instance);
4039 public override bool IsSupportedType(Type type)
4043 throw new ArgumentNullException("type");
4045 return Provider.IsSupportedType(type);
4049 /// A type descriptor for extended types. This type descriptor
4050 /// looks at the head node in the linked list.
4052 private struct DefaultExtendedTypeDescriptor : ICustomTypeDescriptor
4054 private TypeDescriptionNode _node;
4055 private object _instance;
4058 /// Creates a new WalkingExtendedTypeDescriptor.
4060 internal DefaultExtendedTypeDescriptor(TypeDescriptionNode node, object instance)
4063 _instance = instance;
4067 /// ICustomTypeDescriptor implementation.
4069 AttributeCollection ICustomTypeDescriptor.GetAttributes()
4071 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4072 // If so, we can call on it directly rather than creating another
4073 // custom type descriptor
4075 TypeDescriptionProvider p = _node.Provider;
4076 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4079 return rp.GetExtendedAttributes(_instance);
4082 ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4083 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4084 AttributeCollection attrs = desc.GetAttributes();
4085 if (attrs == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetAttributes"));
4090 /// ICustomTypeDescriptor implementation.
4092 string ICustomTypeDescriptor.GetClassName()
4094 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4095 // If so, we can call on it directly rather than creating another
4096 // custom type descriptor
4098 TypeDescriptionProvider p = _node.Provider;
4099 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4102 return rp.GetExtendedClassName(_instance);
4105 ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4106 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4107 string name = desc.GetClassName();
4108 if (name == null) name = _instance.GetType().FullName;
4113 /// ICustomTypeDescriptor implementation.
4115 string ICustomTypeDescriptor.GetComponentName()
4117 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4118 // If so, we can call on it directly rather than creating another
4119 // custom type descriptor
4121 TypeDescriptionProvider p = _node.Provider;
4122 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4125 return rp.GetExtendedComponentName(_instance);
4128 ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4129 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4130 return desc.GetComponentName();
4134 /// ICustomTypeDescriptor implementation.
4136 TypeConverter ICustomTypeDescriptor.GetConverter()
4138 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4139 // If so, we can call on it directly rather than creating another
4140 // custom type descriptor
4142 TypeDescriptionProvider p = _node.Provider;
4143 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4146 return rp.GetExtendedConverter(_instance);
4149 ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4150 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4151 TypeConverter converter = desc.GetConverter();
4152 if (converter == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetConverter"));
4157 /// ICustomTypeDescriptor implementation.
4159 EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
4161 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4162 // If so, we can call on it directly rather than creating another
4163 // custom type descriptor
4165 TypeDescriptionProvider p = _node.Provider;
4166 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4169 return rp.GetExtendedDefaultEvent(_instance);
4172 ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4173 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4174 return desc.GetDefaultEvent();
4178 /// ICustomTypeDescriptor implementation.
4180 PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
4182 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4183 // If so, we can call on it directly rather than creating another
4184 // custom type descriptor
4186 TypeDescriptionProvider p = _node.Provider;
4187 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4190 return rp.GetExtendedDefaultProperty(_instance);
4193 ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4194 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4195 return desc.GetDefaultProperty();
4199 /// ICustomTypeDescriptor implementation.
4201 object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
4203 if (editorBaseType == null)
4205 throw new ArgumentNullException("editorBaseType");
4208 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4209 // If so, we can call on it directly rather than creating another
4210 // custom type descriptor
4212 TypeDescriptionProvider p = _node.Provider;
4213 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4216 return rp.GetExtendedEditor(_instance, editorBaseType);
4219 ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4220 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4221 return desc.GetEditor(editorBaseType);
4225 /// ICustomTypeDescriptor implementation.
4227 EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
4229 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4230 // If so, we can call on it directly rather than creating another
4231 // custom type descriptor
4233 TypeDescriptionProvider p = _node.Provider;
4234 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4237 return rp.GetExtendedEvents(_instance);
4240 ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4241 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4242 EventDescriptorCollection events = desc.GetEvents();
4243 if (events == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetEvents"));
4248 /// ICustomTypeDescriptor implementation.
4250 EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
4252 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4253 // If so, we can call on it directly rather than creating another
4254 // custom type descriptor
4256 TypeDescriptionProvider p = _node.Provider;
4257 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4260 // There is no need to filter these events. For extended objects, they
4261 // are accessed through our pipeline code, which always filters before
4262 // returning. So any filter we do here is redundant. Note that we do
4263 // pass a valid filter to a custom descriptor so it can optimize if it wants.
4264 EventDescriptorCollection events = rp.GetExtendedEvents(_instance);
4268 ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4269 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4270 EventDescriptorCollection evts = desc.GetEvents(attributes);
4271 if (evts == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetEvents"));
4276 /// ICustomTypeDescriptor implementation.
4278 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
4280 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4281 // If so, we can call on it directly rather than creating another
4282 // custom type descriptor
4284 TypeDescriptionProvider p = _node.Provider;
4285 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4288 return rp.GetExtendedProperties(_instance);
4291 ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4292 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4293 PropertyDescriptorCollection properties = desc.GetProperties();
4294 if (properties == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetProperties"));
4299 /// ICustomTypeDescriptor implementation.
4301 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
4303 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4304 // If so, we can call on it directly rather than creating another
4305 // custom type descriptor
4307 TypeDescriptionProvider p = _node.Provider;
4308 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4311 // There is no need to filter these properties. For extended objects, they
4312 // are accessed through our pipeline code, which always filters before
4313 // returning. So any filter we do here is redundant. Note that we do
4314 // pass a valid filter to a custom descriptor so it can optimize if it wants.
4315 PropertyDescriptorCollection props = rp.GetExtendedProperties(_instance);
4319 ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4320 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4321 PropertyDescriptorCollection properties = desc.GetProperties(attributes);
4322 if (properties == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetProperties"));
4327 /// ICustomTypeDescriptor implementation.
4329 object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
4331 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4332 // If so, we can call on it directly rather than creating another
4333 // custom type descriptor
4335 TypeDescriptionProvider p = _node.Provider;
4336 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4339 return rp.GetExtendedPropertyOwner(_instance, pd);
4342 ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
4343 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
4344 object owner = desc.GetPropertyOwner(pd);
4345 if (owner == null) owner = _instance;
4351 /// The default type descriptor.
4353 private struct DefaultTypeDescriptor : ICustomTypeDescriptor
4355 private TypeDescriptionNode _node;
4356 private Type _objectType;
4357 private object _instance;
4360 /// Creates a new WalkingTypeDescriptor.
4362 internal DefaultTypeDescriptor(TypeDescriptionNode node, Type objectType, object instance)
4365 _objectType = objectType;
4366 _instance = instance;
4370 /// ICustomTypeDescriptor implementation.
4372 AttributeCollection ICustomTypeDescriptor.GetAttributes()
4374 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4375 // If so, we can call on it directly rather than creating another
4376 // custom type descriptor
4378 TypeDescriptionProvider p = _node.Provider;
4379 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4380 AttributeCollection attrs;
4383 attrs = rp.GetAttributes(_objectType);
4386 ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4387 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4388 attrs = desc.GetAttributes();
4389 if (attrs == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetAttributes"));
4396 /// ICustomTypeDescriptor implementation.
4398 string ICustomTypeDescriptor.GetClassName()
4400 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4401 // If so, we can call on it directly rather than creating another
4402 // custom type descriptor
4404 TypeDescriptionProvider p = _node.Provider;
4405 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4409 name = rp.GetClassName(_objectType);
4412 ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4413 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4414 name = desc.GetClassName();
4415 if (name == null) name = _objectType.FullName;
4422 /// ICustomTypeDescriptor implementation.
4424 string ICustomTypeDescriptor.GetComponentName()
4426 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4427 // If so, we can call on it directly rather than creating another
4428 // custom type descriptor
4430 TypeDescriptionProvider p = _node.Provider;
4431 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4435 name = rp.GetComponentName(_objectType, _instance);
4438 ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4439 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4440 name = desc.GetComponentName();
4447 /// ICustomTypeDescriptor implementation.
4449 TypeConverter ICustomTypeDescriptor.GetConverter()
4451 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4452 // If so, we can call on it directly rather than creating another
4453 // custom type descriptor
4455 TypeDescriptionProvider p = _node.Provider;
4456 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4457 TypeConverter converter;
4460 converter = rp.GetConverter(_objectType, _instance);
4463 ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4464 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4465 converter = desc.GetConverter();
4466 if (converter == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetConverter"));
4473 /// ICustomTypeDescriptor implementation.
4475 EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
4477 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4478 // If so, we can call on it directly rather than creating another
4479 // custom type descriptor
4481 TypeDescriptionProvider p = _node.Provider;
4482 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4483 EventDescriptor defaultEvent;
4486 defaultEvent = rp.GetDefaultEvent(_objectType, _instance);
4489 ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4490 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4491 defaultEvent = desc.GetDefaultEvent();
4494 return defaultEvent;
4498 /// ICustomTypeDescriptor implementation.
4500 PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
4502 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4503 // If so, we can call on it directly rather than creating another
4504 // custom type descriptor
4506 TypeDescriptionProvider p = _node.Provider;
4507 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4508 PropertyDescriptor defaultProperty;
4511 defaultProperty = rp.GetDefaultProperty(_objectType, _instance);
4514 ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4515 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4516 defaultProperty = desc.GetDefaultProperty();
4519 return defaultProperty;
4523 /// ICustomTypeDescriptor implementation.
4525 object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
4527 if (editorBaseType == null)
4529 throw new ArgumentNullException("editorBaseType");
4532 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4533 // If so, we can call on it directly rather than creating another
4534 // custom type descriptor
4536 TypeDescriptionProvider p = _node.Provider;
4537 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4541 editor = rp.GetEditor(_objectType, _instance, editorBaseType);
4544 ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4545 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4546 editor = desc.GetEditor(editorBaseType);
4553 /// ICustomTypeDescriptor implementation.
4555 EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
4557 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4558 // If so, we can call on it directly rather than creating another
4559 // custom type descriptor
4561 TypeDescriptionProvider p = _node.Provider;
4562 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4563 EventDescriptorCollection events;
4566 events = rp.GetEvents(_objectType);
4569 ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4570 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4571 events = desc.GetEvents();
4572 if (events == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetEvents"));
4579 /// ICustomTypeDescriptor implementation.
4581 EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
4583 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4584 // If so, we can call on it directly rather than creating another
4585 // custom type descriptor
4587 TypeDescriptionProvider p = _node.Provider;
4588 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4589 EventDescriptorCollection events;
4592 events = rp.GetEvents(_objectType);
4595 ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4596 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4597 events = desc.GetEvents(attributes);
4598 if (events == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetEvents"));
4605 /// ICustomTypeDescriptor implementation.
4607 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
4609 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4610 // If so, we can call on it directly rather than creating another
4611 // custom type descriptor
4613 TypeDescriptionProvider p = _node.Provider;
4614 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4615 PropertyDescriptorCollection properties;
4618 properties = rp.GetProperties(_objectType);
4621 ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4622 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4623 properties = desc.GetProperties();
4624 if (properties == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetProperties"));
4631 /// ICustomTypeDescriptor implementation.
4633 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
4635 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4636 // If so, we can call on it directly rather than creating another
4637 // custom type descriptor
4639 TypeDescriptionProvider p = _node.Provider;
4640 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4641 PropertyDescriptorCollection properties;
4644 properties = rp.GetProperties(_objectType);
4647 ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4648 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4649 properties = desc.GetProperties(attributes);
4650 if (properties == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetProperties"));
4657 /// ICustomTypeDescriptor implementation.
4659 object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
4661 // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
4662 // If so, we can call on it directly rather than creating another
4663 // custom type descriptor
4665 TypeDescriptionProvider p = _node.Provider;
4666 ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
4670 owner = rp.GetPropertyOwner(_objectType, _instance, pd);
4673 ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
4674 if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
4675 owner = desc.GetPropertyOwner(pd);
4676 if (owner == null) owner = _instance;
4685 /// This is a simple internal type that allows external parties
4686 /// to public ina custom type description provider for COM
4689 [TypeDescriptionProvider("System.Windows.Forms.ComponentModel.Com2Interop.ComNativeDescriptor, " + AssemblyRef.SystemWindowsForms)]
4690 private sealed class TypeDescriptorComObject
4695 /// This is a simple internal type that allows external parties to
4696 /// register a custom type description provider for all interface types.
4698 private sealed class TypeDescriptorInterface