1 //------------------------------------------------------------------------------
2 // <copyright file="ReflectTypeDescriptionProvider.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
7 namespace System.ComponentModel {
10 using System.Collections;
11 using System.Collections.Generic;
12 using System.Collections.Specialized;
13 using System.ComponentModel.Design;
14 using System.Diagnostics;
15 using System.Globalization;
16 using System.Reflection;
17 using System.Security;
18 using System.Security.Permissions;
21 /// This type description provider provides type information through
22 /// reflection. Unless someone has provided a custom type description
23 /// provider for a type or instance, or unless an instance implements
24 /// ICustomTypeDescriptor, any query for type information will go through
25 /// this class. There should be a single instance of this class associated
26 /// with "object", as it can provide all type information for any type.
28 [HostProtection(SharedState = true)]
29 internal sealed class ReflectTypeDescriptionProvider : TypeDescriptionProvider {
31 // Hastable of Type -> ReflectedTypeData. ReflectedTypeData contains all
32 // of the type information we have gathered for a given type.
34 private Hashtable _typeData;
36 // This is the signature we look for when creating types that are generic, but
37 // want to know what type they are dealing with. Enums are a good example of this;
38 // there is one enum converter that can work with all enums, but it needs to know
39 // the type of enum it is dealing with.
41 private static Type[] _typeConstructor = new Type[] {typeof(Type)};
43 // This is where we store the various converters, etc for the intrinsic types.
45 private static volatile Hashtable _editorTables;
46 private static volatile Hashtable _intrinsicTypeConverters;
48 // For converters, etc that are bound to class attribute data, rather than a class
49 // type, we have special key sentinel values that we put into the hash table.
51 private static object _intrinsicReferenceKey = new object();
52 private static object _intrinsicNullableKey = new object();
54 // The key we put into IDictionaryService to store our cache dictionary.
56 private static object _dictionaryKey = new object();
58 // This is a cache on top of core reflection. The cache
59 // builds itself recursively, so if you ask for the properties
60 // on Control, Component and object are also automatically filled
61 // in. The keys to the property and event caches are types.
62 // The keys to the attribute cache are either MemberInfos or types.
64 private static volatile Hashtable _propertyCache;
65 private static volatile Hashtable _eventCache;
66 private static volatile Hashtable _attributeCache;
67 private static volatile Hashtable _extendedPropertyCache;
69 // These are keys we stuff into our object cache. We use this
70 // cache data to store extender provider info for an object.
72 private static readonly Guid _extenderProviderKey = Guid.NewGuid();
73 private static readonly Guid _extenderPropertiesKey = Guid.NewGuid();
74 private static readonly Guid _extenderProviderPropertiesKey = Guid.NewGuid();
76 // These are attribute that, when we discover them on interfaces, we do
77 // not merge them into the attribute set for a class.
78 private static readonly Type[] _skipInterfaceAttributeList = new Type[]
80 typeof(System.Runtime.InteropServices.GuidAttribute),
81 typeof(System.Runtime.InteropServices.ComVisibleAttribute),
82 typeof(System.Runtime.InteropServices.InterfaceTypeAttribute)
86 internal static Guid ExtenderProviderKey {
88 return _extenderProviderKey;
93 private static object _internalSyncObject = new object();
95 /// Creates a new ReflectTypeDescriptionProvider. The type is the
96 /// type we will obtain type information for.
98 internal ReflectTypeDescriptionProvider()
100 TypeDescriptor.Trace("Reflect : Creating ReflectTypeDescriptionProvider");
104 /// This is a table we create for intrinsic types.
105 /// There should be entries here ONLY for intrinsic
106 /// types, as all other types we should be able to
107 /// add attributes directly as metadata.
109 private static Hashtable IntrinsicTypeConverters {
111 // It is not worth taking a lock for this -- worst case of a collision
112 // would build two tables, one that garbage collects very quickly.
114 if (_intrinsicTypeConverters == null) {
115 Hashtable temp = new Hashtable();
117 // Add the intrinsics
119 temp[typeof(bool)] = typeof(BooleanConverter);
120 temp[typeof(byte)] = typeof(ByteConverter);
121 temp[typeof(SByte)] = typeof(SByteConverter);
122 temp[typeof(char)] = typeof(CharConverter);
123 temp[typeof(double)] = typeof(DoubleConverter);
124 temp[typeof(string)] = typeof(StringConverter);
125 temp[typeof(int)] = typeof(Int32Converter);
126 temp[typeof(short)] = typeof(Int16Converter);
127 temp[typeof(long)] = typeof(Int64Converter);
128 temp[typeof(float)] = typeof(SingleConverter);
129 temp[typeof(UInt16)] = typeof(UInt16Converter);
130 temp[typeof(UInt32)] = typeof(UInt32Converter);
131 temp[typeof(UInt64)] = typeof(UInt64Converter);
132 temp[typeof(object)] = typeof(TypeConverter);
133 temp[typeof(void)] = typeof(TypeConverter);
134 temp[typeof(CultureInfo)] = typeof(CultureInfoConverter);
135 temp[typeof(DateTime)] = typeof(DateTimeConverter);
136 temp[typeof(DateTimeOffset)] = typeof(DateTimeOffsetConverter);
137 temp[typeof(Decimal)] = typeof(DecimalConverter);
138 temp[typeof(TimeSpan)] = typeof(TimeSpanConverter);
139 temp[typeof(Guid)] = typeof(GuidConverter);
140 temp[typeof(Array)] = typeof(ArrayConverter);
141 temp[typeof(ICollection)] = typeof(CollectionConverter);
142 temp[typeof(Enum)] = typeof(EnumConverter);
144 // Special cases for things that are not bound to a specific type
146 temp[_intrinsicReferenceKey] = typeof(ReferenceConverter);
147 temp[_intrinsicNullableKey] = typeof(NullableConverter);
149 _intrinsicTypeConverters = temp;
151 return _intrinsicTypeConverters;
156 /// Adds an editor table for the given editor base type.
157 /// ypically, editors are specified as metadata on an object. If no metadata for a
158 /// equested editor base type can be found on an object, however, the
159 /// ypeDescriptor will search an editor
160 /// able for the editor type, if one can be found.
162 internal static void AddEditorTable(Type editorBaseType, Hashtable table)
164 if (editorBaseType == null)
166 throw new ArgumentNullException("editorBaseType");
171 Debug.Fail("COMPAT: Editor table should not be null");
172 // don't throw; RTM didn't so we can't do it either.
175 lock(_internalSyncObject)
177 if (_editorTables == null)
179 _editorTables = new Hashtable(4);
182 if (!_editorTables.ContainsKey(editorBaseType))
184 _editorTables[editorBaseType] = table;
190 /// CreateInstance implementation. We delegate to Activator.
192 public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)
194 Debug.Assert(objectType != null, "Should have arg-checked before coming in here");
198 if (argTypes != null)
200 obj = SecurityUtils.SecureConstructorInvoke(objectType, argTypes, args, true, BindingFlags.ExactBinding);
204 argTypes = new Type[args.Length];
205 for(int idx = 0; idx < args.Length; idx++) {
206 if (args[idx] != null) {
207 argTypes[idx] = args[idx].GetType();
210 argTypes[idx] = typeof(object);
215 argTypes = new Type[0];
218 obj = SecurityUtils.SecureConstructorInvoke(objectType, argTypes, args, true);
222 obj = SecurityUtils.SecureCreateInstance(objectType, args);
230 /// Helper method to create editors and type converters. This checks to see if the
231 /// type implements a Type constructor, and if it does it invokes that ctor.
232 /// Otherwise, it just tries to create the type.
234 private static object CreateInstance(Type objectType, Type callingType) {
235 object obj = SecurityUtils.SecureConstructorInvoke(objectType, _typeConstructor, new object[] {callingType}, false);
238 obj = SecurityUtils.SecureCreateInstance(objectType);
245 /// Retrieves custom attributes.
247 internal AttributeCollection GetAttributes(Type type)
249 ReflectedTypeData td = GetTypeData(type, true);
250 return td.GetAttributes();
254 /// Our implementation of GetCache sits on top of IDictionaryService.
256 public override IDictionary GetCache(object instance)
258 IComponent comp = instance as IComponent;
259 if (comp != null && comp.Site != null)
261 IDictionaryService ds = comp.Site.GetService(typeof(IDictionaryService)) as IDictionaryService;
264 IDictionary dict = ds.GetValue(_dictionaryKey) as IDictionary;
267 dict = new Hashtable();
268 ds.SetValue(_dictionaryKey, dict);
278 /// Retrieves the class name for our type.
280 internal string GetClassName(Type type)
282 ReflectedTypeData td = GetTypeData(type, true);
283 return td.GetClassName(null);
287 /// Retrieves the component name from the site.
289 internal string GetComponentName(Type type, object instance)
291 ReflectedTypeData td = GetTypeData(type, true);
292 return td.GetComponentName(instance);
296 /// Retrieves the type converter. If instance is non-null,
297 /// it will be used to retrieve attributes. Otherwise, _type
300 internal TypeConverter GetConverter(Type type, object instance)
302 ReflectedTypeData td = GetTypeData(type, true);
303 return td.GetConverter(instance);
307 /// Return the default event. The default event is determined by the
308 /// presence of a DefaultEventAttribute on the class.
310 internal EventDescriptor GetDefaultEvent(Type type, object instance)
312 ReflectedTypeData td = GetTypeData(type, true);
313 return td.GetDefaultEvent(instance);
317 /// Return the default property.
319 internal PropertyDescriptor GetDefaultProperty(Type type, object instance)
321 ReflectedTypeData td = GetTypeData(type, true);
322 return td.GetDefaultProperty(instance);
326 /// Retrieves the editor for the given base type.
328 internal object GetEditor(Type type, object instance, Type editorBaseType)
330 ReflectedTypeData td = GetTypeData(type, true);
331 return td.GetEditor(instance, editorBaseType);
335 /// Retrieves a default editor table for the given editor base type.
337 private static Hashtable GetEditorTable(Type editorBaseType) {
339 if (_editorTables == null)
341 lock(_internalSyncObject)
343 if (_editorTables == null)
345 _editorTables = new Hashtable(4);
350 object table = _editorTables[editorBaseType];
354 // Before we give up, it is possible that the
355 // class initializer for editorBaseType hasn't
358 System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(editorBaseType.TypeHandle);
359 table = _editorTables[editorBaseType];
361 // If the table is still null, then throw a
362 // sentinel in there so we don't
363 // go through this again.
367 lock (_internalSyncObject)
369 table = _editorTables[editorBaseType];
372 _editorTables[editorBaseType] = _editorTables;
378 // Look for our sentinel value that indicates
379 // we have already tried and failed to get
382 if (table == _editorTables)
387 return (Hashtable)table;
391 /// Retrieves the events for this type.
393 internal EventDescriptorCollection GetEvents(Type type)
395 ReflectedTypeData td = GetTypeData(type, true);
396 return td.GetEvents();
400 /// Retrieves custom extender attributes. We don't support
401 /// extender attributes, so we always return an empty collection.
403 internal AttributeCollection GetExtendedAttributes(object instance)
405 return AttributeCollection.Empty;
409 /// Retrieves the class name for our type.
411 internal string GetExtendedClassName(object instance)
413 return GetClassName(instance.GetType());
417 /// Retrieves the component name from the site.
419 internal string GetExtendedComponentName(object instance)
421 return GetComponentName(instance.GetType(), instance);
425 /// Retrieves the type converter. If instance is non-null,
426 /// it will be used to retrieve attributes. Otherwise, _type
429 internal TypeConverter GetExtendedConverter(object instance)
431 return GetConverter(instance.GetType(), instance);
435 /// Return the default event. The default event is determined by the
436 /// presence of a DefaultEventAttribute on the class.
438 internal EventDescriptor GetExtendedDefaultEvent(object instance)
440 return null; // we don't support extended events.
444 /// Return the default property.
446 internal PropertyDescriptor GetExtendedDefaultProperty(object instance)
448 return null; // extender properties are never the default.
452 /// Retrieves the editor for the given base type.
454 internal object GetExtendedEditor(object instance, Type editorBaseType)
456 return GetEditor(instance.GetType(), instance, editorBaseType);
460 /// Retrieves the events for this type.
462 internal EventDescriptorCollection GetExtendedEvents(object instance)
464 return EventDescriptorCollection.Empty;
468 /// Retrieves the properties for this type.
470 internal PropertyDescriptorCollection GetExtendedProperties(object instance)
472 // Is this object a sited component? If not, then it
473 // doesn't have any extender properties.
475 Type componentType = instance.GetType();
477 // Check the component for extender providers. We prefer
478 // IExtenderListService, but will use the container if that's
479 // all we have. In either case, we check the list of extenders
480 // against previously stored data in the object cache. If
481 // the cache is up to date, we just return the extenders in the
484 IExtenderProvider[] extenders = GetExtenderProviders(instance);
485 IDictionary cache = TypeDescriptor.GetCache(instance);
487 if (extenders.Length == 0)
489 return PropertyDescriptorCollection.Empty;
492 // Ok, we have a set of extenders. Now, check to see if there
493 // are properties already in our object cache. If there aren't,
494 // then we will need to create them.
496 PropertyDescriptorCollection properties = null;
500 properties = cache[_extenderPropertiesKey] as PropertyDescriptorCollection;
503 if (properties != null)
508 // Unlike normal properties, it is fine for there to be properties with
509 // duplicate names here.
511 ArrayList propertyList = null;
513 for (int idx = 0; idx < extenders.Length; idx++)
515 PropertyDescriptor[] propertyArray = ReflectGetExtendedProperties(extenders[idx]);
517 if (propertyList == null)
519 propertyList = new ArrayList(propertyArray.Length * extenders.Length);
522 for (int propIdx = 0; propIdx < propertyArray.Length; propIdx++)
524 PropertyDescriptor prop = propertyArray[propIdx];
525 ExtenderProvidedPropertyAttribute eppa = prop.Attributes[typeof(ExtenderProvidedPropertyAttribute)] as ExtenderProvidedPropertyAttribute;
527 Debug.Assert(eppa != null, "Extender property " + prop.Name + " has no provider attribute. We will skip it.");
530 Type receiverType = eppa.ReceiverType;
531 if (receiverType != null)
534 if (receiverType.IsAssignableFrom(componentType))
536 propertyList.Add(prop);
543 // propertyHash now contains ExtendedPropertyDescriptor objects
544 // for each extended property.
546 if (propertyList != null)
548 TypeDescriptor.Trace("Extenders : Allocating property collection for {0} properties", propertyList.Count);
549 PropertyDescriptor[] fullArray = new PropertyDescriptor[propertyList.Count];
550 propertyList.CopyTo(fullArray, 0);
551 properties = new PropertyDescriptorCollection(fullArray, true);
555 properties = PropertyDescriptorCollection.Empty;
560 TypeDescriptor.Trace("Extenders : caching extender results");
561 cache[_extenderPropertiesKey] = properties;
567 protected internal override IExtenderProvider[] GetExtenderProviders(object instance)
569 if (instance == null)
571 throw new ArgumentNullException("instance");
574 IComponent component = instance as IComponent;
575 if (component != null && component.Site != null)
577 IExtenderListService extenderList = component.Site.GetService(typeof(IExtenderListService)) as IExtenderListService;
578 IDictionary cache = TypeDescriptor.GetCache(instance);
580 if (extenderList != null)
582 return GetExtenders(extenderList.GetExtenderProviders(), instance, cache);
586 IContainer cont = component.Site.Container;
589 return GetExtenders(cont.Components, instance, cache);
593 return new IExtenderProvider[0];
597 /// GetExtenders builds a list of extender providers from
598 /// a collection of components. It validates the extenders
599 /// against any cached collection of extenders in the
600 /// cache. If there is a discrepancy, this will erase
601 /// any cached extender properties from the cache and
602 /// save the updated extender list. If there is no
603 /// discrepancy this will simply return the cached list.
605 private static IExtenderProvider[] GetExtenders(ICollection components, object instance, IDictionary cache)
607 bool newExtenders = false;
608 int extenderCount = 0;
609 IExtenderProvider[] existingExtenders = null;
611 //CanExtend is expensive. We will remember results of CanExtend for the first 64 extenders and using "long canExtend" as a bit vector.
612 // we want to avoid memory allocation as well so we don't use some more sophisticated data structure like an array of booleans
613 UInt64 canExtend = 0;
614 int maxCanExtendResults = 64;
615 // currentExtenders is what we intend to return. If the caller passed us
616 // the return value from IExtenderListService, components will already be
617 // an IExtenderProvider[]. If not, then we must treat components as an
618 // opaque collection. We spend a great deal of energy here to avoid
619 // copying or allocating memory because this method is called every
620 // time a component is asked for its properties.
621 IExtenderProvider[] currentExtenders = components as IExtenderProvider[];
625 existingExtenders = cache[_extenderProviderKey] as IExtenderProvider[];
628 if (existingExtenders == null)
636 if (currentExtenders != null)
638 for (curIdx = 0; curIdx < currentExtenders.Length; curIdx++)
640 if (currentExtenders[curIdx].CanExtend(instance))
643 // Performance:We would like to call CanExtend as little as possible therefore we remember its result
644 if (curIdx < maxCanExtendResults)
645 canExtend |= (UInt64)1 << curIdx;
646 if (!newExtenders && (idx >= existingExtenders.Length || currentExtenders[curIdx] != existingExtenders[idx++]))
653 else if (components != null)
655 foreach(object obj in components)
657 IExtenderProvider prov = obj as IExtenderProvider;
658 if (prov != null && prov.CanExtend(instance))
661 if (curIdx < maxCanExtendResults)
662 canExtend |= (UInt64)1<<curIdx;
663 if (!newExtenders && (idx >= existingExtenders.Length || prov != existingExtenders[idx++]))
671 if (existingExtenders != null && extenderCount != existingExtenders.Length)
677 TypeDescriptor.Trace("Extenders : object has new extenders : {0}", instance.GetType().Name);
678 TypeDescriptor.Trace("Extenders : Identified {0} extender providers", extenderCount);
679 if (currentExtenders == null || extenderCount != currentExtenders.Length)
681 IExtenderProvider[] newExtenderArray = new IExtenderProvider[extenderCount];
686 if (currentExtenders != null && extenderCount > 0)
688 while(curIdx < currentExtenders.Length)
690 if ((curIdx < maxCanExtendResults && (canExtend & ((UInt64)1 << curIdx)) != 0 )||
691 (curIdx >= maxCanExtendResults && currentExtenders[curIdx].CanExtend(instance)))
693 Debug.Assert(idx < extenderCount, "There are more extenders than we expect");
694 newExtenderArray[idx++] = currentExtenders[curIdx];
698 Debug.Assert(idx == extenderCount, "Wrong number of extenders");
700 else if (extenderCount > 0)
702 IEnumerator componentEnum = components.GetEnumerator();
703 while(componentEnum.MoveNext())
705 IExtenderProvider p = componentEnum.Current as IExtenderProvider;
707 if (p != null && ((curIdx < maxCanExtendResults && (canExtend & ((UInt64)1 << curIdx)) != 0) ||
708 (curIdx >= maxCanExtendResults && p.CanExtend(instance))))
710 Debug.Assert(idx < extenderCount, "There are more extenders than we expect");
711 newExtenderArray[idx++] = p;
715 Debug.Assert(idx == extenderCount, "Wrong number of extenders");
717 currentExtenders = newExtenderArray;
722 TypeDescriptor.Trace("Extenders : caching extender provider results");
723 cache[_extenderProviderKey] = currentExtenders;
724 cache.Remove(_extenderPropertiesKey);
729 currentExtenders = existingExtenders;
731 return currentExtenders;
735 /// Retrieves the owner for a property.
737 internal object GetExtendedPropertyOwner(object instance, PropertyDescriptor pd)
739 return GetPropertyOwner(instance.GetType(), instance, pd);
742 //////////////////////////////////////////////////////////
744 /// Provides a type descriptor for the given object. We only support this
745 /// if the object is a component that
747 public override ICustomTypeDescriptor GetExtendedTypeDescriptor(object instance)
749 Debug.Fail("This should never be invoked. TypeDescriptionNode should wrap for us.");
754 /// The name of the specified component, or null if the component has no name.
755 /// In many cases this will return the same value as GetComponentName. If the
756 /// component resides in a nested container or has other nested semantics, it may
757 /// return a different fully qualfied name.
759 /// If not overridden, the default implementation of this method will call
760 /// GetComponentName.
762 public override string GetFullComponentName(object component) {
763 IComponent comp = component as IComponent;
765 INestedSite ns = comp.Site as INestedSite;
771 return TypeDescriptor.GetComponentName(component);
775 /// Returns an array of types we have populated metadata for that live
776 /// in the current module.
778 internal Type[] GetPopulatedTypes(Module module) {
779 ArrayList typeList = new ArrayList();;
781 foreach(DictionaryEntry de in _typeData) {
782 Type type = (Type)de.Key;
783 ReflectedTypeData typeData = (ReflectedTypeData)de.Value;
785 if (type.Module == module && typeData.IsPopulated) {
790 return (Type[])typeList.ToArray(typeof(Type));
794 /// Retrieves the properties for this type.
796 internal PropertyDescriptorCollection GetProperties(Type type)
798 ReflectedTypeData td = GetTypeData(type, true);
799 return td.GetProperties();
803 /// Retrieves the owner for a property.
805 internal object GetPropertyOwner(Type type, object instance, PropertyDescriptor pd)
807 return TypeDescriptor.GetAssociation(type, instance);
811 /// Returns an Type for the given type. Since type implements IReflect,
812 /// we just return objectType.
814 public override Type GetReflectionType(Type objectType, object instance)
816 Debug.Assert(objectType != null, "Should have arg-checked before coming in here");
821 /// Returns the type data for the given type, or
822 /// null if there is no type data for the type yet and
823 /// createIfNeeded is false.
825 private ReflectedTypeData GetTypeData(Type type, bool createIfNeeded) {
827 ReflectedTypeData td = null;
829 if (_typeData != null) {
830 td = (ReflectedTypeData)_typeData[type];
836 lock (_internalSyncObject) {
837 if (_typeData != null) {
838 td = (ReflectedTypeData)_typeData[type];
841 if (td == null && createIfNeeded) {
842 td = new ReflectedTypeData(type);
843 if (_typeData == null) {
844 _typeData = new Hashtable();
846 _typeData[type] = td;
854 /// This method returns a custom type descriptor for the given type / object.
855 /// The objectType parameter is always valid, but the instance parameter may
856 /// be null if no instance was passed to TypeDescriptor. The method should
857 /// return a custom type descriptor for the object. If the method is not
858 /// interested in providing type information for the object it should
861 public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
863 Debug.Fail("This should never be invoked. TypeDescriptionNode should wrap for us.");
868 /// Retrieves a type from a name.
870 private static Type GetTypeFromName(string typeName)
872 Type t = Type.GetType(typeName);
876 int commaIndex = typeName.IndexOf(',');
878 if (commaIndex != -1)
880 // At design time, it's possible for us to reuse
881 // an assembly but add new types. The app domain
882 // will cache the assembly based on identity, however,
883 // so it could be looking in the previous version
884 // of the assembly and not finding the type. We work
885 // around this by looking for the non-assembly qualified
886 // name, which causes the domain to raise a type
889 t = Type.GetType(typeName.Substring(0, commaIndex));
897 /// This method returns true if the data cache in this reflection
898 /// type descriptor has data in it.
900 internal bool IsPopulated(Type type)
902 ReflectedTypeData td = GetTypeData(type, false);
904 return td.IsPopulated;
910 /// Static helper API around reflection to get and cache
911 /// custom attributes. This does not recurse, but it will
912 /// walk interfaces on the type. Interfaces are added
913 /// to the end, so merging should be done from length - 1
916 private static Attribute[] ReflectGetAttributes(Type type)
918 if (_attributeCache == null)
920 lock (_internalSyncObject)
922 if (_attributeCache == null)
924 _attributeCache = new Hashtable();
929 Attribute[] attrs = (Attribute[])_attributeCache[type];
935 lock (_internalSyncObject)
937 attrs = (Attribute[])_attributeCache[type];
940 TypeDescriptor.Trace("Attributes : Building attributes for {0}", type.Name);
942 // Get the type's attributes.
944 object[] typeAttrs = type.GetCustomAttributes(typeof(Attribute), false);
946 attrs = new Attribute[typeAttrs.Length];
947 typeAttrs.CopyTo(attrs, 0);
949 _attributeCache[type] = attrs;
957 /// Static helper API around reflection to get and cache
958 /// custom attributes. This does not recurse to the base class.
960 internal static Attribute[] ReflectGetAttributes(MemberInfo member)
962 if (_attributeCache == null)
964 lock (_internalSyncObject)
966 if (_attributeCache == null)
968 _attributeCache = new Hashtable();
973 Attribute[] attrs = (Attribute[])_attributeCache[member];
979 lock (_internalSyncObject)
981 attrs = (Attribute[])_attributeCache[member];
984 // Get the member's attributes.
986 object[] memberAttrs = member.GetCustomAttributes(typeof(Attribute), false);
987 attrs = new Attribute[memberAttrs.Length];
988 memberAttrs.CopyTo(attrs, 0);
989 _attributeCache[member] = attrs;
997 /// Static helper API around reflection to get and cache
998 /// events. This does not recurse to the base class.
1000 private static EventDescriptor[] ReflectGetEvents(Type type)
1002 if (_eventCache == null)
1004 lock (_internalSyncObject)
1006 if (_eventCache == null)
1008 _eventCache = new Hashtable();
1013 EventDescriptor[] events = (EventDescriptor[])_eventCache[type];
1019 lock (_internalSyncObject)
1021 events = (EventDescriptor[])_eventCache[type];
1024 BindingFlags bindingFlags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance;
1025 TypeDescriptor.Trace("Events : Building events for {0}", type.Name);
1027 // Get the type's events. Events may have their add and
1028 // remove methods individually overridden in a derived
1029 // class, but at some point in the base class chain both
1030 // methods must exist. If we find an event that doesn't
1031 // have both add and remove, we skip it here, because it
1032 // will be picked up in our base class scan.
1034 EventInfo[] eventInfos = type.GetEvents(bindingFlags);
1035 events = new EventDescriptor[eventInfos.Length];
1038 for (int idx = 0; idx < eventInfos.Length; idx++)
1040 EventInfo eventInfo = eventInfos[idx];
1042 // GetEvents returns events that are on nonpublic types
1043 // if those types are from our assembly. Screen these.
1045 if ((!(eventInfo.DeclaringType.IsPublic || eventInfo.DeclaringType.IsNestedPublic)) && (eventInfo.DeclaringType.Assembly == typeof(ReflectTypeDescriptionProvider).Assembly)) {
1046 Debug.Fail("Hey, assumption holds true. Rip this assert.");
1050 MethodInfo addMethod = eventInfo.GetAddMethod();
1051 MethodInfo removeMethod = eventInfo.GetRemoveMethod();
1053 if (addMethod != null && removeMethod != null)
1055 events[eventCount++] = new ReflectEventDescriptor(type, eventInfo);
1059 if (eventCount != events.Length)
1061 EventDescriptor[] newEvents = new EventDescriptor[eventCount];
1062 Array.Copy(events, 0, newEvents, 0, eventCount);
1067 foreach(EventDescriptor dbgEvent in events)
1069 Debug.Assert(dbgEvent != null, "Holes in event array for type " + type);
1072 _eventCache[type] = events;
1080 /// This performs the actual reflection needed to discover
1081 /// extender properties. If object caching is supported this
1082 /// will maintain a cache of property descriptors on the
1083 /// extender provider. Extender properties are actually two
1084 /// property descriptors in one. There is a chunk of per-class
1085 /// data in a ReflectPropertyDescriptor that defines the
1086 /// parameter types and get and set methods of the extended property,
1087 /// and there is an ExtendedPropertyDescriptor that combines this
1088 /// with an extender provider object to create what looks like a
1089 /// normal property. ReflectGetExtendedProperties maintains two
1090 /// separate caches for these two sets: a static one for the
1091 /// ReflectPropertyDescriptor values that don't change for each
1092 /// provider instance, and a per-provider cache that contains
1093 /// the ExtendedPropertyDescriptors.
1095 private static PropertyDescriptor[] ReflectGetExtendedProperties(IExtenderProvider provider)
1097 IDictionary cache = TypeDescriptor.GetCache(provider);
1098 PropertyDescriptor[] properties;
1102 properties = cache[_extenderProviderPropertiesKey] as PropertyDescriptor[];
1103 if (properties != null)
1109 // Our per-instance cache missed. We have never seen this instance of the
1110 // extender provider before. See if we can find our class-based
1113 if (_extendedPropertyCache == null)
1115 lock (_internalSyncObject)
1117 if (_extendedPropertyCache == null)
1119 _extendedPropertyCache = new Hashtable();
1124 Type providerType = provider.GetType();
1125 ReflectPropertyDescriptor[] extendedProperties = (ReflectPropertyDescriptor[])_extendedPropertyCache[providerType];
1126 if (extendedProperties == null)
1128 lock (_internalSyncObject)
1130 extendedProperties = (ReflectPropertyDescriptor[])_extendedPropertyCache[providerType];
1132 // Our class-based property store failed as well, so we need to build up the set of
1133 // extended properties here.
1135 if (extendedProperties == null)
1137 AttributeCollection attributes = TypeDescriptor.GetAttributes(providerType);
1138 ArrayList extendedList = new ArrayList(attributes.Count);
1140 foreach(Attribute attr in attributes)
1142 ProvidePropertyAttribute provideAttr = attr as ProvidePropertyAttribute;
1144 if (provideAttr != null)
1146 Type receiverType = GetTypeFromName(provideAttr.ReceiverTypeName);
1148 if (receiverType != null)
1150 MethodInfo getMethod = providerType.GetMethod("Get" + provideAttr.PropertyName, new Type[] {receiverType});
1152 if (getMethod != null && !getMethod.IsStatic && getMethod.IsPublic)
1154 MethodInfo setMethod = providerType.GetMethod("Set" + provideAttr.PropertyName, new Type[] {receiverType, getMethod.ReturnType});
1156 if (setMethod != null && (setMethod.IsStatic || !setMethod.IsPublic))
1161 extendedList.Add(new ReflectPropertyDescriptor(providerType, provideAttr.PropertyName, getMethod.ReturnType, receiverType, getMethod, setMethod, null));
1167 extendedProperties = new ReflectPropertyDescriptor[extendedList.Count];
1168 extendedList.CopyTo(extendedProperties, 0);
1169 _extendedPropertyCache[providerType] = extendedProperties;
1174 // Now that we have our extended properties we can build up a list of callable properties. These can be
1175 // returned to the user.
1177 properties = new PropertyDescriptor[extendedProperties.Length];
1178 for (int idx = 0; idx < extendedProperties.Length; idx++)
1180 Attribute[] attrs = null;
1181 IComponent comp = provider as IComponent;
1182 if (comp == null || comp.Site == null)
1184 attrs = new Attribute[] {DesignOnlyAttribute.Yes};
1187 ReflectPropertyDescriptor rpd = extendedProperties[idx];
1188 ExtendedPropertyDescriptor epd = new ExtendedPropertyDescriptor(rpd, rpd.ExtenderGetReceiverType(), provider, attrs);
1189 properties[idx] = epd;
1194 cache[_extenderProviderPropertiesKey] = properties;
1201 /// Static helper API around reflection to get and cache
1202 /// properties. This does not recurse to the base class.
1204 private static PropertyDescriptor[] ReflectGetProperties(Type type)
1206 if (_propertyCache == null)
1208 lock(_internalSyncObject)
1210 if (_propertyCache == null)
1212 _propertyCache = new Hashtable();
1217 PropertyDescriptor[] properties = (PropertyDescriptor[])_propertyCache[type];
1218 if (properties != null)
1223 lock (_internalSyncObject)
1225 properties = (PropertyDescriptor[])_propertyCache[type];
1227 if (properties == null)
1229 BindingFlags bindingFlags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance;
1230 TypeDescriptor.Trace("Properties : Building properties for {0}", type.Name);
1232 // Get the type's properties. Properties may have their
1233 // get and set methods individually overridden in a derived
1234 // class, so if we find a missing method we need to walk
1235 // down the base class chain to find it. We actually merge
1236 // "new" properties of the same name, so we must preserve
1237 // the member info for each method individually.
1239 PropertyInfo[] propertyInfos = type.GetProperties(bindingFlags);
1240 properties = new PropertyDescriptor[propertyInfos.Length];
1241 int propertyCount = 0;
1244 for (int idx = 0; idx < propertyInfos.Length; idx++)
1246 PropertyInfo propertyInfo = propertyInfos[idx];
1248 // Today we do not support parameterized properties.
1250 if (propertyInfo.GetIndexParameters().Length > 0) {
1254 MethodInfo getMethod = propertyInfo.GetGetMethod();
1255 MethodInfo setMethod = propertyInfo.GetSetMethod();
1256 string name = propertyInfo.Name;
1258 // If the property only overrode "set", then we don't
1259 // pick it up here. Rather, we just merge it in from
1260 // the base class list.
1263 // If a property had at least a get method, we consider it. We don't
1264 // consider write-only properties.
1266 if (getMethod != null)
1268 properties[propertyCount++] = new ReflectPropertyDescriptor(type, name,
1269 propertyInfo.PropertyType,
1270 propertyInfo, getMethod,
1276 if (propertyCount != properties.Length)
1278 PropertyDescriptor[] newProperties = new PropertyDescriptor[propertyCount];
1279 Array.Copy(properties, 0, newProperties, 0, propertyCount);
1280 properties = newProperties;
1284 foreach(PropertyDescriptor dbgProp in properties)
1286 Debug.Assert(dbgProp != null, "Holes in property array for type " + type);
1289 _propertyCache[type] = properties;
1297 /// Refreshes the contents of this type descriptor. This does not
1298 /// actually requery, but it will clear our state so the next
1299 /// query re-populates.
1301 internal void Refresh(Type type)
1303 ReflectedTypeData td = GetTypeData(type, false);
1310 /// Searches the provided intrinsic hashtable for a match with the object type.
1311 /// At the beginning, the hashtable contains types for the various converters.
1312 /// As this table is searched, the types for these objects
1313 /// are replaced with instances, so we only create as needed. This method
1314 /// does the search up the base class hierarchy and will create instances
1315 /// for types as needed. These instances are stored back into the table
1316 /// for the base type, and for the original component type, for fast access.
1318 private static object SearchIntrinsicTable(Hashtable table, Type callingType)
1320 object hashEntry = null;
1322 // We take a lock on this table. Nothing in this code calls out to
1323 // other methods that lock, so it should be fairly safe to grab this
1324 // lock. Also, this allows multiple intrinsic tables to be searched
1329 Type baseType = callingType;
1330 while (baseType != null && baseType != typeof(object))
1332 hashEntry = table[baseType];
1334 // If the entry is a late-bound type, then try to
1337 string typeString = hashEntry as string;
1338 if (typeString != null)
1340 hashEntry = Type.GetType(typeString);
1341 if (hashEntry != null)
1343 table[baseType] = hashEntry;
1347 if (hashEntry != null)
1352 baseType = baseType.BaseType;
1355 // Now make a scan through each value in the table, looking for interfaces.
1356 // If we find one, see if the object implements the interface.
1358 if (hashEntry == null)
1361 foreach(DictionaryEntry de in table)
1363 Type keyType = de.Key as Type;
1365 if (keyType != null && keyType.IsInterface && keyType.IsAssignableFrom(callingType))
1368 hashEntry = de.Value;
1369 string typeString = hashEntry as string;
1371 if (typeString != null)
1373 hashEntry = Type.GetType(typeString);
1374 if (hashEntry != null)
1376 table[callingType] = hashEntry;
1380 if (hashEntry != null)
1388 // Special case converters
1390 if (hashEntry == null)
1392 if (callingType.IsGenericType && callingType.GetGenericTypeDefinition() == typeof(Nullable<>))
1394 // Check if it is a nullable value
1395 hashEntry = table[_intrinsicNullableKey];
1397 else if (callingType.IsInterface)
1399 // Finally, check to see if the component type is some unknown interface.
1400 // We have a custom converter for that.
1401 hashEntry = table[_intrinsicReferenceKey];
1405 // Interfaces do not derive from object, so we
1406 // must handle the case of no hash entry here.
1408 if (hashEntry == null)
1410 hashEntry = table[typeof(object)];
1413 // If the entry is a type, create an instance of it and then
1414 // replace the entry. This way we only need to create once.
1415 // We can only do this if the object doesn't want a type
1416 // in its constructor.
1418 Type type = hashEntry as Type;
1422 hashEntry = CreateInstance(type, callingType);
1423 if (type.GetConstructor(_typeConstructor) == null)
1425 table[callingType] = hashEntry;
1434 /// This class contains all the reflection information for a
1437 private class ReflectedTypeData {
1440 private AttributeCollection _attributes;
1441 private EventDescriptorCollection _events;
1442 private PropertyDescriptorCollection _properties;
1443 private TypeConverter _converter;
1444 private object[] _editors;
1445 private Type[] _editorTypes;
1446 private int _editorCount;
1448 internal ReflectedTypeData(Type type) {
1450 TypeDescriptor.Trace("Reflect : Creating ReflectedTypeData for {0}", type.Name);
1454 /// This method returns true if the data cache in this reflection
1455 /// type descriptor has data in it.
1457 internal bool IsPopulated
1461 return (_attributes != null) | (_events != null) | (_properties != null);
1466 /// Retrieves custom attributes.
1468 internal AttributeCollection GetAttributes()
1470 // Worst case collision scenario: we don't want the perf hit
1471 // of taking a lock, so if we collide we will query for
1472 // attributes twice. Not a big deal.
1474 if (_attributes == null)
1476 TypeDescriptor.Trace("Attributes : Building collection for {0}", _type.Name);
1478 // Obtaining attributes follows a very critical order: we must take care that
1479 // we merge attributes the right way. Consider this:
1485 // interface IDerived;
1488 // class Base : IBase;
1491 // class Derived : Base, IDerived
1493 // Calling GetAttributes on type Derived must merge attributes in the following
1494 // order: A1 - A4. Interfaces always lose to types, and interfaces and types
1495 // must be merged in the same order. At the same time, we must be careful
1496 // that we don't always go through reflection here, because someone could have
1497 // created a custom provider for a type. Because there is only one instance
1498 // of ReflectTypeDescriptionProvider created for typeof(object), if our code
1499 // is invoked here we can be sure that there is no custom provider for
1500 // _type all the way up the base class chain.
1501 // We cannot be sure that there is no custom provider for
1502 // interfaces that _type implements, however, because they are not derived
1503 // from _type. So, for interfaces, we must go through TypeDescriptor
1504 // again to get the interfaces attributes.
1506 // Get the type's attributes. This does not recurse up the base class chain.
1507 // We append base class attributes to this array so when walking we will
1508 // walk from Length - 1 to zero.
1510 Attribute[] attrArray = ReflectTypeDescriptionProvider.ReflectGetAttributes(_type);
1511 Type baseType = _type.BaseType;
1513 while (baseType != null && baseType != typeof(object))
1515 Attribute[] baseArray = ReflectTypeDescriptionProvider.ReflectGetAttributes(baseType);
1516 Attribute[] temp = new Attribute[attrArray.Length + baseArray.Length];
1517 Array.Copy(attrArray, 0, temp, 0, attrArray.Length);
1518 Array.Copy(baseArray, 0, temp, attrArray.Length, baseArray.Length);
1520 baseType = baseType.BaseType;
1523 // Next, walk the type's interfaces. We append these to
1524 // the attribute array as well.
1526 int ifaceStartIdx = attrArray.Length;
1527 Type[] interfaces = _type.GetInterfaces();
1528 TypeDescriptor.Trace("Attributes : Walking {0} interfaces", interfaces.Length);
1529 for(int idx = 0; idx < interfaces.Length; idx++)
1531 Type iface = interfaces[idx];
1533 // only do this for public interfaces.
1535 if ((iface.Attributes & (TypeAttributes.Public | TypeAttributes.NestedPublic)) != 0) {
1536 // No need to pass an instance into GetTypeDescriptor here because, if someone provided a custom
1537 // provider based on object, it already would have hit.
1538 AttributeCollection ifaceAttrs = TypeDescriptor.GetAttributes(iface);
1539 if (ifaceAttrs.Count > 0) {
1540 Attribute[] temp = new Attribute[attrArray.Length + ifaceAttrs.Count];
1541 Array.Copy(attrArray, 0, temp, 0, attrArray.Length);
1542 ifaceAttrs.CopyTo(temp, attrArray.Length);
1548 // Finally, put all these attributes in a dictionary and filter out the duplicates.
1550 OrderedDictionary attrDictionary = new OrderedDictionary(attrArray.Length);
1552 for (int idx = 0; idx < attrArray.Length; idx++)
1554 bool addAttr = true;
1555 if (idx >= ifaceStartIdx) {
1556 for (int ifaceSkipIdx = 0; ifaceSkipIdx < _skipInterfaceAttributeList.Length; ifaceSkipIdx++)
1558 if (_skipInterfaceAttributeList[ifaceSkipIdx].IsInstanceOfType(attrArray[idx]))
1567 if (addAttr && !attrDictionary.Contains(attrArray[idx].TypeId)) {
1568 attrDictionary[attrArray[idx].TypeId] = attrArray[idx];
1572 attrArray = new Attribute[attrDictionary.Count];
1573 attrDictionary.Values.CopyTo(attrArray, 0);
1574 _attributes = new AttributeCollection(attrArray);
1581 /// Retrieves the class name for our type.
1583 internal string GetClassName(object instance)
1585 return _type.FullName;
1589 /// Retrieves the component name from the site.
1591 internal string GetComponentName(object instance)
1593 IComponent comp = instance as IComponent;
1596 ISite site = comp.Site;
1599 INestedSite nestedSite = site as INestedSite;
1600 if (nestedSite != null)
1602 return nestedSite.FullName;
1615 /// Retrieves the type converter. If instance is non-null,
1616 /// it will be used to retrieve attributes. Otherwise, _type
1619 internal TypeConverter GetConverter(object instance)
1621 TypeConverterAttribute typeAttr = null;
1623 // For instances, the design time object for them may want to redefine the
1624 // attributes. So, we search the attribute here based on the instance. If found,
1625 // we then search on the same attribute based on type. If the two don't match, then
1626 // we cannot cache the value and must re-create every time. It is rare for a designer
1627 // to override these attributes, so we want to be smart here.
1629 if (instance != null)
1631 typeAttr = (TypeConverterAttribute)TypeDescriptor.GetAttributes(_type)[typeof(TypeConverterAttribute)];
1632 TypeConverterAttribute instanceAttr = (TypeConverterAttribute)TypeDescriptor.GetAttributes(instance)[typeof(TypeConverterAttribute)];
1633 if (typeAttr != instanceAttr)
1635 Type converterType = GetTypeFromName(instanceAttr.ConverterTypeName);
1636 if (converterType != null && typeof(TypeConverter).IsAssignableFrom(converterType))
1638 #if MONO_FEATURE_CAS
1640 IntSecurity.FullReflection.Assert();
1642 return (TypeConverter)ReflectTypeDescriptionProvider.CreateInstance(converterType, _type);
1643 #if MONO_FEATURE_CAS
1645 CodeAccessPermission.RevertAssert();
1652 // If we got here, we return our type-based converter.
1654 if (_converter == null)
1656 TypeDescriptor.Trace("Converters : Building converter for {0}", _type.Name);
1658 if (typeAttr == null)
1660 typeAttr = (TypeConverterAttribute)TypeDescriptor.GetAttributes(_type)[typeof(TypeConverterAttribute)];
1663 if (typeAttr != null)
1665 Type converterType = GetTypeFromName(typeAttr.ConverterTypeName);
1666 if (converterType != null && typeof(TypeConverter).IsAssignableFrom(converterType))
1668 #if MONO_FEATURE_CAS
1670 IntSecurity.FullReflection.Assert();
1672 _converter = (TypeConverter)ReflectTypeDescriptionProvider.CreateInstance(converterType, _type);
1673 #if MONO_FEATURE_CAS
1675 CodeAccessPermission.RevertAssert();
1681 if (_converter == null)
1683 // We did not get a converter. Traverse up the base class chain until
1684 // we find one in the stock hashtable.
1686 _converter = (TypeConverter)ReflectTypeDescriptionProvider.SearchIntrinsicTable(IntrinsicTypeConverters, _type);
1687 Debug.Assert(_converter != null, "There is no intrinsic setup in the hashtable for the Object type");
1695 /// Return the default event. The default event is determined by the
1696 /// presence of a DefaultEventAttribute on the class.
1698 internal EventDescriptor GetDefaultEvent(object instance)
1700 AttributeCollection attributes;
1702 if (instance != null)
1704 attributes = TypeDescriptor.GetAttributes(instance);
1708 attributes = TypeDescriptor.GetAttributes(_type);
1711 DefaultEventAttribute attr = (DefaultEventAttribute)attributes[typeof(DefaultEventAttribute)];
1712 if (attr != null && attr.Name != null)
1714 if (instance != null)
1716 return TypeDescriptor.GetEvents(instance)[attr.Name];
1720 return TypeDescriptor.GetEvents(_type)[attr.Name];
1728 /// Return the default property.
1730 internal PropertyDescriptor GetDefaultProperty(object instance)
1732 AttributeCollection attributes;
1734 if (instance != null)
1736 attributes = TypeDescriptor.GetAttributes(instance);
1740 attributes = TypeDescriptor.GetAttributes(_type);
1743 DefaultPropertyAttribute attr = (DefaultPropertyAttribute)attributes[typeof(DefaultPropertyAttribute)];
1744 if (attr != null && attr.Name != null)
1746 if (instance != null)
1748 return TypeDescriptor.GetProperties(instance)[attr.Name];
1752 return TypeDescriptor.GetProperties(_type)[attr.Name];
1760 /// Retrieves the editor for the given base type.
1762 internal object GetEditor(object instance, Type editorBaseType)
1764 EditorAttribute typeAttr;
1766 // For instances, the design time object for them may want to redefine the
1767 // attributes. So, we search the attribute here based on the instance. If found,
1768 // we then search on the same attribute based on type. If the two don't match, then
1769 // we cannot cache the value and must re-create every time. It is rare for a designer
1770 // to override these attributes, so we want to be smart here.
1772 if (instance != null)
1774 typeAttr = GetEditorAttribute(TypeDescriptor.GetAttributes(_type), editorBaseType);
1775 EditorAttribute instanceAttr = GetEditorAttribute(TypeDescriptor.GetAttributes(instance), editorBaseType);
1776 if (typeAttr != instanceAttr)
1778 Type editorType = GetTypeFromName(instanceAttr.EditorTypeName);
1779 if (editorType != null && editorBaseType.IsAssignableFrom(editorType))
1781 return ReflectTypeDescriptionProvider.CreateInstance(editorType, _type);
1786 // If we got here, we return our type-based editor.
1790 for (int idx = 0; idx < _editorCount; idx++)
1792 if (_editorTypes[idx] == editorBaseType)
1794 return _editors[idx];
1799 // Editor is not cached yet. Look in the attributes.
1801 object editor = null;
1803 typeAttr = GetEditorAttribute(TypeDescriptor.GetAttributes(_type), editorBaseType);
1804 if (typeAttr != null)
1806 Type editorType = GetTypeFromName(typeAttr.EditorTypeName);
1807 if (editorType != null && editorBaseType.IsAssignableFrom(editorType))
1809 editor = ReflectTypeDescriptionProvider.CreateInstance(editorType, _type);
1813 // Editor is not in the attributes. Search intrinsic tables.
1817 Hashtable intrinsicEditors = ReflectTypeDescriptionProvider.GetEditorTable(editorBaseType);
1818 if (intrinsicEditors != null)
1820 editor = ReflectTypeDescriptionProvider.SearchIntrinsicTable(intrinsicEditors, _type);
1823 // As a quick sanity check, check to see that the editor we got back is of
1824 // the correct type.
1826 if (editor != null && !editorBaseType.IsInstanceOfType(editor)) {
1827 Debug.Fail("Editor " + editor.GetType().FullName + " is not an instance of " + editorBaseType.FullName + " but it is in that base types table.");
1836 if (_editorTypes == null || _editorTypes.Length == _editorCount)
1838 int newLength = (_editorTypes == null ? 4 : _editorTypes.Length * 2);
1840 Type[] newTypes = new Type[newLength];
1841 object[] newEditors = new object[newLength];
1843 if (_editorTypes != null)
1845 _editorTypes.CopyTo(newTypes, 0);
1846 _editors.CopyTo(newEditors, 0);
1849 _editorTypes = newTypes;
1850 _editors = newEditors;
1852 _editorTypes[_editorCount] = editorBaseType;
1853 _editors[_editorCount++] = editor;
1862 /// Helper method to return an editor attribute of the correct base type.
1864 private static EditorAttribute GetEditorAttribute(AttributeCollection attributes, Type editorBaseType)
1866 foreach(Attribute attr in attributes)
1868 EditorAttribute edAttr = attr as EditorAttribute;
1871 Type attrEditorBaseType = Type.GetType(edAttr.EditorBaseTypeName);
1873 if (attrEditorBaseType != null && attrEditorBaseType == editorBaseType)
1884 /// Retrieves the events for this type.
1886 internal EventDescriptorCollection GetEvents()
1888 // Worst case collision scenario: we don't want the perf hit
1889 // of taking a lock, so if we collide we will query for
1890 // events twice. Not a big deal.
1892 if (_events == null)
1894 TypeDescriptor.Trace("Events : Building collection for {0}", _type.Name);
1896 EventDescriptor[] eventArray;
1897 Dictionary<string, EventDescriptor> eventList = new Dictionary<string, EventDescriptor>(16);
1898 Type baseType = _type;
1899 Type objType = typeof(object);
1902 eventArray = ReflectGetEvents(baseType);
1903 foreach(EventDescriptor ed in eventArray) {
1904 if (!eventList.ContainsKey(ed.Name)) {
1905 eventList.Add(ed.Name, ed);
1908 baseType = baseType.BaseType;
1910 while(baseType != null && baseType != objType);
1912 eventArray = new EventDescriptor[eventList.Count];
1913 eventList.Values.CopyTo(eventArray, 0);
1914 _events = new EventDescriptorCollection(eventArray, true);
1921 /// Retrieves the properties for this type.
1923 internal PropertyDescriptorCollection GetProperties()
1925 // Worst case collision scenario: we don't want the perf hit
1926 // of taking a lock, so if we collide we will query for
1927 // properties twice. Not a big deal.
1929 if (_properties == null)
1931 TypeDescriptor.Trace("Properties : Building collection for {0}", _type.Name);
1933 PropertyDescriptor[] propertyArray;
1934 Dictionary<string, PropertyDescriptor> propertyList = new Dictionary<string, PropertyDescriptor>(10);
1935 Type baseType = _type;
1936 Type objType = typeof(object);
1939 propertyArray = ReflectGetProperties(baseType);
1940 foreach(PropertyDescriptor p in propertyArray) {
1941 if (!propertyList.ContainsKey(p.Name)) {
1942 propertyList.Add(p.Name, p);
1945 baseType = baseType.BaseType;
1947 while(baseType != null && baseType != objType);
1949 propertyArray = new PropertyDescriptor[propertyList.Count];
1950 propertyList.Values.CopyTo(propertyArray, 0);
1951 _properties = new PropertyDescriptorCollection(propertyArray, true);
1958 /// Retrieves a type from a name. The Assembly of the type
1959 /// that this PropertyDescriptor came from is first checked,
1960 /// then a global Type.GetType is performed.
1962 private Type GetTypeFromName(string typeName)
1965 if (typeName == null || typeName.Length == 0)
1970 int commaIndex = typeName.IndexOf(',');
1973 if (commaIndex == -1)
1975 t = _type.Assembly.GetType(typeName);
1980 t = Type.GetType(typeName);
1983 if (t == null && commaIndex != -1)
1985 // At design time, it's possible for us to reuse
1986 // an assembly but add new types. The app domain
1987 // will cache the assembly based on identity, however,
1988 // so it could be looking in the previous version
1989 // of the assembly and not finding the type. We work
1990 // around this by looking for the non-assembly qualified
1991 // name, which causes the domain to raise a type
1994 t = Type.GetType(typeName.Substring(0, commaIndex));
2001 /// Refreshes the contents of this type descriptor. This does not
2002 /// actually requery, but it will clear our state so the next
2003 /// query re-populates.
2005 internal void Refresh()
2012 _editorTypes = null;