1 //------------------------------------------------------------------------------ 2 // <copyright file="ReflectTypeDescriptionProvider.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 //------------------------------------------------------------------------------ 6 7 namespace System.ComponentModel { 8 9 using System; 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; 19 20 /// <devdoc> 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. 27 /// </devdoc> 28 [HostProtection(SharedState = true)] 29 internal sealed class ReflectTypeDescriptionProvider : TypeDescriptionProvider { 30 31 // Hastable of Type -> ReflectedTypeData. ReflectedTypeData contains all 32 // of the type information we have gathered for a given type. 33 // 34 private Hashtable _typeData; 35 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. 40 // 41 private static Type[] _typeConstructor = new Type[] {typeof(Type)}; 42 43 // This is where we store the various converters, etc for the intrinsic types. 44 // 45 private static volatile Hashtable _editorTables; 46 private static volatile Hashtable _intrinsicTypeConverters; 47 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. 50 // 51 private static object _intrinsicReferenceKey = new object(); 52 private static object _intrinsicNullableKey = new object(); 53 54 // The key we put into IDictionaryService to store our cache dictionary. 55 // 56 private static object _dictionaryKey = new object(); 57 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. 63 // 64 private static volatile Hashtable _propertyCache; 65 private static volatile Hashtable _eventCache; 66 private static volatile Hashtable _attributeCache; 67 private static volatile Hashtable _extendedPropertyCache; 68 69 // These are keys we stuff into our object cache. We use this 70 // cache data to store extender provider info for an object. 71 // 72 private static readonly Guid _extenderProviderKey = Guid.NewGuid(); 73 private static readonly Guid _extenderPropertiesKey = Guid.NewGuid(); 74 private static readonly Guid _extenderProviderPropertiesKey = Guid.NewGuid(); 75 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[] 79 { 80 typeof(System.Runtime.InteropServices.GuidAttribute), 81 typeof(System.Runtime.InteropServices.ComVisibleAttribute), 82 typeof(System.Runtime.InteropServices.InterfaceTypeAttribute) 83 }; 84 85 86 internal static Guid ExtenderProviderKey { 87 get { 88 return _extenderProviderKey; 89 } 90 } 91 92 93 private static object _internalSyncObject = new object(); 94 /// <devdoc> 95 /// Creates a new ReflectTypeDescriptionProvider. The type is the 96 /// type we will obtain type information for. 97 /// </devdoc> ReflectTypeDescriptionProvider()98 internal ReflectTypeDescriptionProvider() 99 { 100 TypeDescriptor.Trace("Reflect : Creating ReflectTypeDescriptionProvider"); 101 } 102 103 /// <devdoc> 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. 108 /// </devdoc> 109 private static Hashtable IntrinsicTypeConverters { 110 get { 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. 113 // 114 if (_intrinsicTypeConverters == null) { 115 Hashtable temp = new Hashtable(); 116 117 // Add the intrinsics 118 // 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); 143 144 // Special cases for things that are not bound to a specific type 145 // 146 temp[_intrinsicReferenceKey] = typeof(ReferenceConverter); 147 temp[_intrinsicNullableKey] = typeof(NullableConverter); 148 149 _intrinsicTypeConverters = temp; 150 } 151 return _intrinsicTypeConverters; 152 } 153 } 154 155 /// <devdoc> 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. 161 /// </devdoc> AddEditorTable(Type editorBaseType, Hashtable table)162 internal static void AddEditorTable(Type editorBaseType, Hashtable table) 163 { 164 if (editorBaseType == null) 165 { 166 throw new ArgumentNullException("editorBaseType"); 167 } 168 169 if (table == null) 170 { 171 Debug.Fail("COMPAT: Editor table should not be null"); 172 // don't throw; RTM didn't so we can't do it either. 173 } 174 175 lock(_internalSyncObject) 176 { 177 if (_editorTables == null) 178 { 179 _editorTables = new Hashtable(4); 180 } 181 182 if (!_editorTables.ContainsKey(editorBaseType)) 183 { 184 _editorTables[editorBaseType] = table; 185 } 186 } 187 } 188 189 /// <devdoc> 190 /// CreateInstance implementation. We delegate to Activator. 191 /// </devdoc> CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)192 public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args) 193 { 194 Debug.Assert(objectType != null, "Should have arg-checked before coming in here"); 195 196 object obj = null; 197 198 if (argTypes != null) 199 { 200 obj = SecurityUtils.SecureConstructorInvoke(objectType, argTypes, args, true, BindingFlags.ExactBinding); 201 } 202 else { 203 if (args != null) { 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(); 208 } 209 else { 210 argTypes[idx] = typeof(object); 211 } 212 } 213 } 214 else { 215 argTypes = new Type[0]; 216 } 217 218 obj = SecurityUtils.SecureConstructorInvoke(objectType, argTypes, args, true); 219 } 220 221 if (obj == null) { 222 obj = SecurityUtils.SecureCreateInstance(objectType, args); 223 } 224 225 return obj; 226 } 227 228 229 /// <devdoc> 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. 233 /// </devdoc> CreateInstance(Type objectType, Type callingType)234 private static object CreateInstance(Type objectType, Type callingType) { 235 object obj = SecurityUtils.SecureConstructorInvoke(objectType, _typeConstructor, new object[] {callingType}, false); 236 237 if (obj == null) { 238 obj = SecurityUtils.SecureCreateInstance(objectType); 239 } 240 241 return obj; 242 } 243 244 /// <devdoc> 245 /// Retrieves custom attributes. 246 /// </devdoc> GetAttributes(Type type)247 internal AttributeCollection GetAttributes(Type type) 248 { 249 ReflectedTypeData td = GetTypeData(type, true); 250 return td.GetAttributes(); 251 } 252 253 /// <devdoc> 254 /// Our implementation of GetCache sits on top of IDictionaryService. 255 /// </devdoc> GetCache(object instance)256 public override IDictionary GetCache(object instance) 257 { 258 IComponent comp = instance as IComponent; 259 if (comp != null && comp.Site != null) 260 { 261 IDictionaryService ds = comp.Site.GetService(typeof(IDictionaryService)) as IDictionaryService; 262 if (ds != null) 263 { 264 IDictionary dict = ds.GetValue(_dictionaryKey) as IDictionary; 265 if (dict == null) 266 { 267 dict = new Hashtable(); 268 ds.SetValue(_dictionaryKey, dict); 269 } 270 return dict; 271 } 272 } 273 274 return null; 275 } 276 277 /// <devdoc> 278 /// Retrieves the class name for our type. 279 /// </devdoc> GetClassName(Type type)280 internal string GetClassName(Type type) 281 { 282 ReflectedTypeData td = GetTypeData(type, true); 283 return td.GetClassName(null); 284 } 285 286 /// <devdoc> 287 /// Retrieves the component name from the site. 288 /// </devdoc> GetComponentName(Type type, object instance)289 internal string GetComponentName(Type type, object instance) 290 { 291 ReflectedTypeData td = GetTypeData(type, true); 292 return td.GetComponentName(instance); 293 } 294 295 /// <devdoc> 296 /// Retrieves the type converter. If instance is non-null, 297 /// it will be used to retrieve attributes. Otherwise, _type 298 /// will be used. 299 /// </devdoc> GetConverter(Type type, object instance)300 internal TypeConverter GetConverter(Type type, object instance) 301 { 302 ReflectedTypeData td = GetTypeData(type, true); 303 return td.GetConverter(instance); 304 } 305 306 /// <devdoc> 307 /// Return the default event. The default event is determined by the 308 /// presence of a DefaultEventAttribute on the class. 309 /// </devdoc> GetDefaultEvent(Type type, object instance)310 internal EventDescriptor GetDefaultEvent(Type type, object instance) 311 { 312 ReflectedTypeData td = GetTypeData(type, true); 313 return td.GetDefaultEvent(instance); 314 } 315 316 /// <devdoc> 317 /// Return the default property. 318 /// </devdoc> GetDefaultProperty(Type type, object instance)319 internal PropertyDescriptor GetDefaultProperty(Type type, object instance) 320 { 321 ReflectedTypeData td = GetTypeData(type, true); 322 return td.GetDefaultProperty(instance); 323 } 324 325 /// <devdoc> 326 /// Retrieves the editor for the given base type. 327 /// </devdoc> GetEditor(Type type, object instance, Type editorBaseType)328 internal object GetEditor(Type type, object instance, Type editorBaseType) 329 { 330 ReflectedTypeData td = GetTypeData(type, true); 331 return td.GetEditor(instance, editorBaseType); 332 } 333 334 /// <devdoc> 335 /// Retrieves a default editor table for the given editor base type. 336 /// </devdoc> GetEditorTable(Type editorBaseType)337 private static Hashtable GetEditorTable(Type editorBaseType) { 338 339 if (_editorTables == null) 340 { 341 lock(_internalSyncObject) 342 { 343 if (_editorTables == null) 344 { 345 _editorTables = new Hashtable(4); 346 } 347 } 348 } 349 350 object table = _editorTables[editorBaseType]; 351 352 if (table == null) 353 { 354 // Before we give up, it is possible that the 355 // class initializer for editorBaseType hasn't 356 // actually run. 357 // 358 System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(editorBaseType.TypeHandle); 359 table = _editorTables[editorBaseType]; 360 361 // If the table is still null, then throw a 362 // sentinel in there so we don't 363 // go through this again. 364 // 365 if (table == null) 366 { 367 lock (_internalSyncObject) 368 { 369 table = _editorTables[editorBaseType]; 370 if (table == null) 371 { 372 _editorTables[editorBaseType] = _editorTables; 373 } 374 } 375 } 376 } 377 378 // Look for our sentinel value that indicates 379 // we have already tried and failed to get 380 // a table. 381 // 382 if (table == _editorTables) 383 { 384 table = null; 385 } 386 387 return (Hashtable)table; 388 } 389 390 /// <devdoc> 391 /// Retrieves the events for this type. 392 /// </devdoc> GetEvents(Type type)393 internal EventDescriptorCollection GetEvents(Type type) 394 { 395 ReflectedTypeData td = GetTypeData(type, true); 396 return td.GetEvents(); 397 } 398 399 /// <devdoc> 400 /// Retrieves custom extender attributes. We don't support 401 /// extender attributes, so we always return an empty collection. 402 /// </devdoc> GetExtendedAttributes(object instance)403 internal AttributeCollection GetExtendedAttributes(object instance) 404 { 405 return AttributeCollection.Empty; 406 } 407 408 /// <devdoc> 409 /// Retrieves the class name for our type. 410 /// </devdoc> GetExtendedClassName(object instance)411 internal string GetExtendedClassName(object instance) 412 { 413 return GetClassName(instance.GetType()); 414 } 415 416 /// <devdoc> 417 /// Retrieves the component name from the site. 418 /// </devdoc> GetExtendedComponentName(object instance)419 internal string GetExtendedComponentName(object instance) 420 { 421 return GetComponentName(instance.GetType(), instance); 422 } 423 424 /// <devdoc> 425 /// Retrieves the type converter. If instance is non-null, 426 /// it will be used to retrieve attributes. Otherwise, _type 427 /// will be used. 428 /// </devdoc> GetExtendedConverter(object instance)429 internal TypeConverter GetExtendedConverter(object instance) 430 { 431 return GetConverter(instance.GetType(), instance); 432 } 433 434 /// <devdoc> 435 /// Return the default event. The default event is determined by the 436 /// presence of a DefaultEventAttribute on the class. 437 /// </devdoc> GetExtendedDefaultEvent(object instance)438 internal EventDescriptor GetExtendedDefaultEvent(object instance) 439 { 440 return null; // we don't support extended events. 441 } 442 443 /// <devdoc> 444 /// Return the default property. 445 /// </devdoc> GetExtendedDefaultProperty(object instance)446 internal PropertyDescriptor GetExtendedDefaultProperty(object instance) 447 { 448 return null; // extender properties are never the default. 449 } 450 451 /// <devdoc> 452 /// Retrieves the editor for the given base type. 453 /// </devdoc> GetExtendedEditor(object instance, Type editorBaseType)454 internal object GetExtendedEditor(object instance, Type editorBaseType) 455 { 456 return GetEditor(instance.GetType(), instance, editorBaseType); 457 } 458 459 /// <devdoc> 460 /// Retrieves the events for this type. 461 /// </devdoc> GetExtendedEvents(object instance)462 internal EventDescriptorCollection GetExtendedEvents(object instance) 463 { 464 return EventDescriptorCollection.Empty; 465 } 466 467 /// <devdoc> 468 /// Retrieves the properties for this type. 469 /// </devdoc> GetExtendedProperties(object instance)470 internal PropertyDescriptorCollection GetExtendedProperties(object instance) 471 { 472 // Is this object a sited component? If not, then it 473 // doesn't have any extender properties. 474 // 475 Type componentType = instance.GetType(); 476 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 482 // cache. 483 // 484 IExtenderProvider[] extenders = GetExtenderProviders(instance); 485 IDictionary cache = TypeDescriptor.GetCache(instance); 486 487 if (extenders.Length == 0) 488 { 489 return PropertyDescriptorCollection.Empty; 490 } 491 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. 495 // 496 PropertyDescriptorCollection properties = null; 497 498 if (cache != null) 499 { 500 properties = cache[_extenderPropertiesKey] as PropertyDescriptorCollection; 501 } 502 503 if (properties != null) 504 { 505 return properties; 506 } 507 508 // Unlike normal properties, it is fine for there to be properties with 509 // duplicate names here. 510 // 511 ArrayList propertyList = null; 512 513 for (int idx = 0; idx < extenders.Length; idx++) 514 { 515 PropertyDescriptor[] propertyArray = ReflectGetExtendedProperties(extenders[idx]); 516 517 if (propertyList == null) 518 { 519 propertyList = new ArrayList(propertyArray.Length * extenders.Length); 520 } 521 522 for (int propIdx = 0; propIdx < propertyArray.Length; propIdx++) 523 { 524 PropertyDescriptor prop = propertyArray[propIdx]; 525 ExtenderProvidedPropertyAttribute eppa = prop.Attributes[typeof(ExtenderProvidedPropertyAttribute)] as ExtenderProvidedPropertyAttribute; 526 527 Debug.Assert(eppa != null, "Extender property " + prop.Name + " has no provider attribute. We will skip it."); 528 if (eppa != null) 529 { 530 Type receiverType = eppa.ReceiverType; 531 if (receiverType != null) 532 { 533 534 if (receiverType.IsAssignableFrom(componentType)) 535 { 536 propertyList.Add(prop); 537 } 538 } 539 } 540 } 541 } 542 543 // propertyHash now contains ExtendedPropertyDescriptor objects 544 // for each extended property. 545 // 546 if (propertyList != null) 547 { 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); 552 } 553 else 554 { 555 properties = PropertyDescriptorCollection.Empty; 556 } 557 558 if (cache != null) 559 { 560 TypeDescriptor.Trace("Extenders : caching extender results"); 561 cache[_extenderPropertiesKey] = properties; 562 } 563 564 return properties; 565 } 566 GetExtenderProviders(object instance)567 protected internal override IExtenderProvider[] GetExtenderProviders(object instance) 568 { 569 if (instance == null) 570 { 571 throw new ArgumentNullException("instance"); 572 } 573 574 IComponent component = instance as IComponent; 575 if (component != null && component.Site != null) 576 { 577 IExtenderListService extenderList = component.Site.GetService(typeof(IExtenderListService)) as IExtenderListService; 578 IDictionary cache = TypeDescriptor.GetCache(instance); 579 580 if (extenderList != null) 581 { 582 return GetExtenders(extenderList.GetExtenderProviders(), instance, cache); 583 } 584 else 585 { 586 IContainer cont = component.Site.Container; 587 if (cont != null) 588 { 589 return GetExtenders(cont.Components, instance, cache); 590 } 591 } 592 } 593 return new IExtenderProvider[0]; 594 } 595 596 /// <devdoc> 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. 604 /// </devdoc> GetExtenders(ICollection components, object instance, IDictionary cache)605 private static IExtenderProvider[] GetExtenders(ICollection components, object instance, IDictionary cache) 606 { 607 bool newExtenders = false; 608 int extenderCount = 0; 609 IExtenderProvider[] existingExtenders = null; 610 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[]; 622 623 if (cache != null) 624 { 625 existingExtenders = cache[_extenderProviderKey] as IExtenderProvider[]; 626 } 627 628 if (existingExtenders == null) 629 { 630 newExtenders = true; 631 } 632 633 int curIdx = 0; 634 int idx = 0; 635 636 if (currentExtenders != null) 637 { 638 for (curIdx = 0; curIdx < currentExtenders.Length; curIdx++) 639 { 640 if (currentExtenders[curIdx].CanExtend(instance)) 641 { 642 extenderCount++; 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++])) 647 { 648 newExtenders = true; 649 } 650 } 651 } 652 } 653 else if (components != null) 654 { 655 foreach(object obj in components) 656 { 657 IExtenderProvider prov = obj as IExtenderProvider; 658 if (prov != null && prov.CanExtend(instance)) 659 { 660 extenderCount++; 661 if (curIdx < maxCanExtendResults) 662 canExtend |= (UInt64)1<<curIdx; 663 if (!newExtenders && (idx >= existingExtenders.Length || prov != existingExtenders[idx++])) 664 { 665 newExtenders = true; 666 } 667 } 668 curIdx++; 669 } 670 } 671 if (existingExtenders != null && extenderCount != existingExtenders.Length) 672 { 673 newExtenders = true; 674 } 675 if (newExtenders) 676 { 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) 680 { 681 IExtenderProvider[] newExtenderArray = new IExtenderProvider[extenderCount]; 682 683 curIdx = 0; 684 idx = 0; 685 686 if (currentExtenders != null && extenderCount > 0) 687 { 688 while(curIdx < currentExtenders.Length) 689 { 690 if ((curIdx < maxCanExtendResults && (canExtend & ((UInt64)1 << curIdx)) != 0 )|| 691 (curIdx >= maxCanExtendResults && currentExtenders[curIdx].CanExtend(instance))) 692 { 693 Debug.Assert(idx < extenderCount, "There are more extenders than we expect"); 694 newExtenderArray[idx++] = currentExtenders[curIdx]; 695 } 696 curIdx++; 697 } 698 Debug.Assert(idx == extenderCount, "Wrong number of extenders"); 699 } 700 else if (extenderCount > 0) 701 { 702 IEnumerator componentEnum = components.GetEnumerator(); 703 while(componentEnum.MoveNext()) 704 { 705 IExtenderProvider p = componentEnum.Current as IExtenderProvider; 706 707 if (p != null && ((curIdx < maxCanExtendResults && (canExtend & ((UInt64)1 << curIdx)) != 0) || 708 (curIdx >= maxCanExtendResults && p.CanExtend(instance)))) 709 { 710 Debug.Assert(idx < extenderCount, "There are more extenders than we expect"); 711 newExtenderArray[idx++] = p; 712 } 713 curIdx++; 714 } 715 Debug.Assert(idx == extenderCount, "Wrong number of extenders"); 716 } 717 currentExtenders = newExtenderArray; 718 } 719 720 if (cache != null) 721 { 722 TypeDescriptor.Trace("Extenders : caching extender provider results"); 723 cache[_extenderProviderKey] = currentExtenders; 724 cache.Remove(_extenderPropertiesKey); 725 } 726 } 727 else 728 { 729 currentExtenders = existingExtenders; 730 } 731 return currentExtenders; 732 } 733 734 /// <devdoc> 735 /// Retrieves the owner for a property. 736 /// </devdoc> GetExtendedPropertyOwner(object instance, PropertyDescriptor pd)737 internal object GetExtendedPropertyOwner(object instance, PropertyDescriptor pd) 738 { 739 return GetPropertyOwner(instance.GetType(), instance, pd); 740 } 741 742 ////////////////////////////////////////////////////////// 743 /// <devdoc> 744 /// Provides a type descriptor for the given object. We only support this 745 /// if the object is a component that 746 /// </devdoc> GetExtendedTypeDescriptor(object instance)747 public override ICustomTypeDescriptor GetExtendedTypeDescriptor(object instance) 748 { 749 Debug.Fail("This should never be invoked. TypeDescriptionNode should wrap for us."); 750 return null; 751 } 752 753 /// <devdoc> 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. 758 /// 759 /// If not overridden, the default implementation of this method will call 760 /// GetComponentName. 761 /// </devdoc> GetFullComponentName(object component)762 public override string GetFullComponentName(object component) { 763 IComponent comp = component as IComponent; 764 if (comp != null) { 765 INestedSite ns = comp.Site as INestedSite; 766 if (ns != null) { 767 return ns.FullName; 768 } 769 } 770 771 return TypeDescriptor.GetComponentName(component); 772 } 773 774 /// <devdoc> 775 /// Returns an array of types we have populated metadata for that live 776 /// in the current module. 777 /// </devdoc> GetPopulatedTypes(Module module)778 internal Type[] GetPopulatedTypes(Module module) { 779 ArrayList typeList = new ArrayList();; 780 781 foreach(DictionaryEntry de in _typeData) { 782 Type type = (Type)de.Key; 783 ReflectedTypeData typeData = (ReflectedTypeData)de.Value; 784 785 if (type.Module == module && typeData.IsPopulated) { 786 typeList.Add(type); 787 } 788 } 789 790 return (Type[])typeList.ToArray(typeof(Type)); 791 } 792 793 /// <devdoc> 794 /// Retrieves the properties for this type. 795 /// </devdoc> GetProperties(Type type)796 internal PropertyDescriptorCollection GetProperties(Type type) 797 { 798 ReflectedTypeData td = GetTypeData(type, true); 799 return td.GetProperties(); 800 } 801 802 /// <devdoc> 803 /// Retrieves the owner for a property. 804 /// </devdoc> GetPropertyOwner(Type type, object instance, PropertyDescriptor pd)805 internal object GetPropertyOwner(Type type, object instance, PropertyDescriptor pd) 806 { 807 return TypeDescriptor.GetAssociation(type, instance); 808 } 809 810 /// <devdoc> 811 /// Returns an Type for the given type. Since type implements IReflect, 812 /// we just return objectType. 813 /// </devdoc> GetReflectionType(Type objectType, object instance)814 public override Type GetReflectionType(Type objectType, object instance) 815 { 816 Debug.Assert(objectType != null, "Should have arg-checked before coming in here"); 817 return objectType; 818 } 819 820 /// <devdoc> 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. 824 /// </devdoc> GetTypeData(Type type, bool createIfNeeded)825 private ReflectedTypeData GetTypeData(Type type, bool createIfNeeded) { 826 827 ReflectedTypeData td = null; 828 829 if (_typeData != null) { 830 td = (ReflectedTypeData)_typeData[type]; 831 if (td != null) { 832 return td; 833 } 834 } 835 836 lock (_internalSyncObject) { 837 if (_typeData != null) { 838 td = (ReflectedTypeData)_typeData[type]; 839 } 840 841 if (td == null && createIfNeeded) { 842 td = new ReflectedTypeData(type); 843 if (_typeData == null) { 844 _typeData = new Hashtable(); 845 } 846 _typeData[type] = td; 847 } 848 } 849 850 return td; 851 } 852 853 /// <devdoc> 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 859 /// return null. 860 /// </devdoc> GetTypeDescriptor(Type objectType, object instance)861 public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) 862 { 863 Debug.Fail("This should never be invoked. TypeDescriptionNode should wrap for us."); 864 return null; 865 } 866 867 /// <devdoc> 868 /// Retrieves a type from a name. 869 /// </devdoc> GetTypeFromName(string typeName)870 private static Type GetTypeFromName(string typeName) 871 { 872 Type t = Type.GetType(typeName); 873 874 if (t == null) 875 { 876 int commaIndex = typeName.IndexOf(','); 877 878 if (commaIndex != -1) 879 { 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 887 // resolve event. 888 // 889 t = Type.GetType(typeName.Substring(0, commaIndex)); 890 } 891 } 892 893 return t; 894 } 895 896 /// <devdoc> 897 /// This method returns true if the data cache in this reflection 898 /// type descriptor has data in it. 899 /// </devdoc> IsPopulated(Type type)900 internal bool IsPopulated(Type type) 901 { 902 ReflectedTypeData td = GetTypeData(type, false); 903 if (td != null) { 904 return td.IsPopulated; 905 } 906 return false; 907 } 908 909 /// <devdoc> 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 914 /// to 0. 915 /// </devdoc> ReflectGetAttributes(Type type)916 private static Attribute[] ReflectGetAttributes(Type type) 917 { 918 if (_attributeCache == null) 919 { 920 lock (_internalSyncObject) 921 { 922 if (_attributeCache == null) 923 { 924 _attributeCache = new Hashtable(); 925 } 926 } 927 } 928 929 Attribute[] attrs = (Attribute[])_attributeCache[type]; 930 if (attrs != null) 931 { 932 return attrs; 933 } 934 935 lock (_internalSyncObject) 936 { 937 attrs = (Attribute[])_attributeCache[type]; 938 if (attrs == null) 939 { 940 TypeDescriptor.Trace("Attributes : Building attributes for {0}", type.Name); 941 942 // Get the type's attributes. 943 // 944 object[] typeAttrs = type.GetCustomAttributes(typeof(Attribute), false); 945 946 attrs = new Attribute[typeAttrs.Length]; 947 typeAttrs.CopyTo(attrs, 0); 948 949 _attributeCache[type] = attrs; 950 } 951 } 952 953 return attrs; 954 } 955 956 /// <devdoc> 957 /// Static helper API around reflection to get and cache 958 /// custom attributes. This does not recurse to the base class. 959 /// </devdoc> ReflectGetAttributes(MemberInfo member)960 internal static Attribute[] ReflectGetAttributes(MemberInfo member) 961 { 962 if (_attributeCache == null) 963 { 964 lock (_internalSyncObject) 965 { 966 if (_attributeCache == null) 967 { 968 _attributeCache = new Hashtable(); 969 } 970 } 971 } 972 973 Attribute[] attrs = (Attribute[])_attributeCache[member]; 974 if (attrs != null) 975 { 976 return attrs; 977 } 978 979 lock (_internalSyncObject) 980 { 981 attrs = (Attribute[])_attributeCache[member]; 982 if (attrs == null) 983 { 984 // Get the member's attributes. 985 // 986 object[] memberAttrs = member.GetCustomAttributes(typeof(Attribute), false); 987 attrs = new Attribute[memberAttrs.Length]; 988 memberAttrs.CopyTo(attrs, 0); 989 _attributeCache[member] = attrs; 990 } 991 } 992 993 return attrs; 994 } 995 996 /// <devdoc> 997 /// Static helper API around reflection to get and cache 998 /// events. This does not recurse to the base class. 999 /// </devdoc> ReflectGetEvents(Type type)1000 private static EventDescriptor[] ReflectGetEvents(Type type) 1001 { 1002 if (_eventCache == null) 1003 { 1004 lock (_internalSyncObject) 1005 { 1006 if (_eventCache == null) 1007 { 1008 _eventCache = new Hashtable(); 1009 } 1010 } 1011 } 1012 1013 EventDescriptor[] events = (EventDescriptor[])_eventCache[type]; 1014 if (events != null) 1015 { 1016 return events; 1017 } 1018 1019 lock (_internalSyncObject) 1020 { 1021 events = (EventDescriptor[])_eventCache[type]; 1022 if (events == null) 1023 { 1024 BindingFlags bindingFlags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance; 1025 TypeDescriptor.Trace("Events : Building events for {0}", type.Name); 1026 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. 1033 // 1034 EventInfo[] eventInfos = type.GetEvents(bindingFlags); 1035 events = new EventDescriptor[eventInfos.Length]; 1036 int eventCount = 0; 1037 1038 for (int idx = 0; idx < eventInfos.Length; idx++) 1039 { 1040 EventInfo eventInfo = eventInfos[idx]; 1041 1042 // GetEvents returns events that are on nonpublic types 1043 // if those types are from our assembly. Screen these. 1044 // 1045 if ((!(eventInfo.DeclaringType.IsPublic || eventInfo.DeclaringType.IsNestedPublic)) && (eventInfo.DeclaringType.Assembly == typeof(ReflectTypeDescriptionProvider).Assembly)) { 1046 Debug.Fail("Hey, assumption holds true. Rip this assert."); 1047 continue; 1048 } 1049 1050 MethodInfo addMethod = eventInfo.GetAddMethod(); 1051 MethodInfo removeMethod = eventInfo.GetRemoveMethod(); 1052 1053 if (addMethod != null && removeMethod != null) 1054 { 1055 events[eventCount++] = new ReflectEventDescriptor(type, eventInfo); 1056 } 1057 } 1058 1059 if (eventCount != events.Length) 1060 { 1061 EventDescriptor[] newEvents = new EventDescriptor[eventCount]; 1062 Array.Copy(events, 0, newEvents, 0, eventCount); 1063 events = newEvents; 1064 } 1065 1066 #if DEBUG 1067 foreach(EventDescriptor dbgEvent in events) 1068 { 1069 Debug.Assert(dbgEvent != null, "Holes in event array for type " + type); 1070 } 1071 #endif 1072 _eventCache[type] = events; 1073 } 1074 } 1075 1076 return events; 1077 } 1078 1079 /// <devdoc> 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. 1094 /// </devdoc> ReflectGetExtendedProperties(IExtenderProvider provider)1095 private static PropertyDescriptor[] ReflectGetExtendedProperties(IExtenderProvider provider) 1096 { 1097 IDictionary cache = TypeDescriptor.GetCache(provider); 1098 PropertyDescriptor[] properties; 1099 1100 if (cache != null) 1101 { 1102 properties = cache[_extenderProviderPropertiesKey] as PropertyDescriptor[]; 1103 if (properties != null) 1104 { 1105 return properties; 1106 } 1107 } 1108 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 1111 // property store. 1112 // 1113 if (_extendedPropertyCache == null) 1114 { 1115 lock (_internalSyncObject) 1116 { 1117 if (_extendedPropertyCache == null) 1118 { 1119 _extendedPropertyCache = new Hashtable(); 1120 } 1121 } 1122 } 1123 1124 Type providerType = provider.GetType(); 1125 ReflectPropertyDescriptor[] extendedProperties = (ReflectPropertyDescriptor[])_extendedPropertyCache[providerType]; 1126 if (extendedProperties == null) 1127 { 1128 lock (_internalSyncObject) 1129 { 1130 extendedProperties = (ReflectPropertyDescriptor[])_extendedPropertyCache[providerType]; 1131 1132 // Our class-based property store failed as well, so we need to build up the set of 1133 // extended properties here. 1134 // 1135 if (extendedProperties == null) 1136 { 1137 AttributeCollection attributes = TypeDescriptor.GetAttributes(providerType); 1138 ArrayList extendedList = new ArrayList(attributes.Count); 1139 1140 foreach(Attribute attr in attributes) 1141 { 1142 ProvidePropertyAttribute provideAttr = attr as ProvidePropertyAttribute; 1143 1144 if (provideAttr != null) 1145 { 1146 Type receiverType = GetTypeFromName(provideAttr.ReceiverTypeName); 1147 1148 if (receiverType != null) 1149 { 1150 MethodInfo getMethod = providerType.GetMethod("Get" + provideAttr.PropertyName, new Type[] {receiverType}); 1151 1152 if (getMethod != null && !getMethod.IsStatic && getMethod.IsPublic) 1153 { 1154 MethodInfo setMethod = providerType.GetMethod("Set" + provideAttr.PropertyName, new Type[] {receiverType, getMethod.ReturnType}); 1155 1156 if (setMethod != null && (setMethod.IsStatic || !setMethod.IsPublic)) 1157 { 1158 setMethod = null; 1159 } 1160 1161 extendedList.Add(new ReflectPropertyDescriptor(providerType, provideAttr.PropertyName, getMethod.ReturnType, receiverType, getMethod, setMethod, null)); 1162 } 1163 } 1164 } 1165 } 1166 1167 extendedProperties = new ReflectPropertyDescriptor[extendedList.Count]; 1168 extendedList.CopyTo(extendedProperties, 0); 1169 _extendedPropertyCache[providerType] = extendedProperties; 1170 } 1171 } 1172 } 1173 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. 1176 // 1177 properties = new PropertyDescriptor[extendedProperties.Length]; 1178 for (int idx = 0; idx < extendedProperties.Length; idx++) 1179 { 1180 Attribute[] attrs = null; 1181 IComponent comp = provider as IComponent; 1182 if (comp == null || comp.Site == null) 1183 { 1184 attrs = new Attribute[] {DesignOnlyAttribute.Yes}; 1185 } 1186 1187 ReflectPropertyDescriptor rpd = extendedProperties[idx]; 1188 ExtendedPropertyDescriptor epd = new ExtendedPropertyDescriptor(rpd, rpd.ExtenderGetReceiverType(), provider, attrs); 1189 properties[idx] = epd; 1190 } 1191 1192 if (cache != null) 1193 { 1194 cache[_extenderProviderPropertiesKey] = properties; 1195 } 1196 1197 return properties; 1198 } 1199 1200 /// <devdoc> 1201 /// Static helper API around reflection to get and cache 1202 /// properties. This does not recurse to the base class. 1203 /// </devdoc> ReflectGetProperties(Type type)1204 private static PropertyDescriptor[] ReflectGetProperties(Type type) 1205 { 1206 if (_propertyCache == null) 1207 { 1208 lock(_internalSyncObject) 1209 { 1210 if (_propertyCache == null) 1211 { 1212 _propertyCache = new Hashtable(); 1213 } 1214 } 1215 } 1216 1217 PropertyDescriptor[] properties = (PropertyDescriptor[])_propertyCache[type]; 1218 if (properties != null) 1219 { 1220 return properties; 1221 } 1222 1223 lock (_internalSyncObject) 1224 { 1225 properties = (PropertyDescriptor[])_propertyCache[type]; 1226 1227 if (properties == null) 1228 { 1229 BindingFlags bindingFlags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance; 1230 TypeDescriptor.Trace("Properties : Building properties for {0}", type.Name); 1231 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. 1238 // 1239 PropertyInfo[] propertyInfos = type.GetProperties(bindingFlags); 1240 properties = new PropertyDescriptor[propertyInfos.Length]; 1241 int propertyCount = 0; 1242 1243 1244 for (int idx = 0; idx < propertyInfos.Length; idx++) 1245 { 1246 PropertyInfo propertyInfo = propertyInfos[idx]; 1247 1248 // Today we do not support parameterized properties. 1249 // 1250 if (propertyInfo.GetIndexParameters().Length > 0) { 1251 continue; 1252 } 1253 1254 MethodInfo getMethod = propertyInfo.GetGetMethod(); 1255 MethodInfo setMethod = propertyInfo.GetSetMethod(); 1256 string name = propertyInfo.Name; 1257 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. 1261 1262 1263 // If a property had at least a get method, we consider it. We don't 1264 // consider write-only properties. 1265 // 1266 if (getMethod != null) 1267 { 1268 properties[propertyCount++] = new ReflectPropertyDescriptor(type, name, 1269 propertyInfo.PropertyType, 1270 propertyInfo, getMethod, 1271 setMethod, null); 1272 } 1273 } 1274 1275 1276 if (propertyCount != properties.Length) 1277 { 1278 PropertyDescriptor[] newProperties = new PropertyDescriptor[propertyCount]; 1279 Array.Copy(properties, 0, newProperties, 0, propertyCount); 1280 properties = newProperties; 1281 } 1282 1283 #if DEBUG 1284 foreach(PropertyDescriptor dbgProp in properties) 1285 { 1286 Debug.Assert(dbgProp != null, "Holes in property array for type " + type); 1287 } 1288 #endif 1289 _propertyCache[type] = properties; 1290 } 1291 } 1292 1293 return properties; 1294 } 1295 1296 /// <devdoc> 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. 1300 /// </devdoc> Refresh(Type type)1301 internal void Refresh(Type type) 1302 { 1303 ReflectedTypeData td = GetTypeData(type, false); 1304 if (td != null) { 1305 td.Refresh(); 1306 } 1307 } 1308 1309 /// <devdoc> 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. 1317 /// </devdoc> SearchIntrinsicTable(Hashtable table, Type callingType)1318 private static object SearchIntrinsicTable(Hashtable table, Type callingType) 1319 { 1320 object hashEntry = null; 1321 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 1325 // at once. 1326 // 1327 lock(table) 1328 { 1329 Type baseType = callingType; 1330 while (baseType != null && baseType != typeof(object)) 1331 { 1332 hashEntry = table[baseType]; 1333 1334 // If the entry is a late-bound type, then try to 1335 // resolve it. 1336 // 1337 string typeString = hashEntry as string; 1338 if (typeString != null) 1339 { 1340 hashEntry = Type.GetType(typeString); 1341 if (hashEntry != null) 1342 { 1343 table[baseType] = hashEntry; 1344 } 1345 } 1346 1347 if (hashEntry != null) 1348 { 1349 break; 1350 } 1351 1352 baseType = baseType.BaseType; 1353 } 1354 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. 1357 // 1358 if (hashEntry == null) 1359 { 1360 1361 foreach(DictionaryEntry de in table) 1362 { 1363 Type keyType = de.Key as Type; 1364 1365 if (keyType != null && keyType.IsInterface && keyType.IsAssignableFrom(callingType)) 1366 { 1367 1368 hashEntry = de.Value; 1369 string typeString = hashEntry as string; 1370 1371 if (typeString != null) 1372 { 1373 hashEntry = Type.GetType(typeString); 1374 if (hashEntry != null) 1375 { 1376 table[callingType] = hashEntry; 1377 } 1378 } 1379 1380 if (hashEntry != null) 1381 { 1382 break; 1383 } 1384 } 1385 } 1386 } 1387 1388 // Special case converters 1389 // 1390 if (hashEntry == null) 1391 { 1392 if (callingType.IsGenericType && callingType.GetGenericTypeDefinition() == typeof(Nullable<>)) 1393 { 1394 // Check if it is a nullable value 1395 hashEntry = table[_intrinsicNullableKey]; 1396 } 1397 else if (callingType.IsInterface) 1398 { 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]; 1402 } 1403 } 1404 1405 // Interfaces do not derive from object, so we 1406 // must handle the case of no hash entry here. 1407 // 1408 if (hashEntry == null) 1409 { 1410 hashEntry = table[typeof(object)]; 1411 } 1412 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. 1417 // 1418 Type type = hashEntry as Type; 1419 1420 if (type != null) 1421 { 1422 hashEntry = CreateInstance(type, callingType); 1423 if (type.GetConstructor(_typeConstructor) == null) 1424 { 1425 table[callingType] = hashEntry; 1426 } 1427 } 1428 } 1429 1430 return hashEntry; 1431 } 1432 1433 /// <devdoc> 1434 /// This class contains all the reflection information for a 1435 /// given type. 1436 /// </devdoc> 1437 private class ReflectedTypeData { 1438 1439 private Type _type; 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; 1447 ReflectedTypeData(Type type)1448 internal ReflectedTypeData(Type type) { 1449 _type = type; 1450 TypeDescriptor.Trace("Reflect : Creating ReflectedTypeData for {0}", type.Name); 1451 } 1452 1453 /// <devdoc> 1454 /// This method returns true if the data cache in this reflection 1455 /// type descriptor has data in it. 1456 /// </devdoc> 1457 internal bool IsPopulated 1458 { 1459 get 1460 { 1461 return (_attributes != null) | (_events != null) | (_properties != null); 1462 } 1463 } 1464 1465 /// <devdoc> 1466 /// Retrieves custom attributes. 1467 /// </devdoc> GetAttributes()1468 internal AttributeCollection GetAttributes() 1469 { 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. 1473 // 1474 if (_attributes == null) 1475 { 1476 TypeDescriptor.Trace("Attributes : Building collection for {0}", _type.Name); 1477 1478 // Obtaining attributes follows a very critical order: we must take care that 1479 // we merge attributes the right way. Consider this: 1480 // 1481 // [A4] 1482 // interface IBase; 1483 // 1484 // [A3] 1485 // interface IDerived; 1486 // 1487 // [A2] 1488 // class Base : IBase; 1489 // 1490 // [A1] 1491 // class Derived : Base, IDerived 1492 // 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. 1505 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. 1509 // 1510 Attribute[] attrArray = ReflectTypeDescriptionProvider.ReflectGetAttributes(_type); 1511 Type baseType = _type.BaseType; 1512 1513 while (baseType != null && baseType != typeof(object)) 1514 { 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); 1519 attrArray = temp; 1520 baseType = baseType.BaseType; 1521 } 1522 1523 // Next, walk the type's interfaces. We append these to 1524 // the attribute array as well. 1525 // 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++) 1530 { 1531 Type iface = interfaces[idx]; 1532 1533 // only do this for public interfaces. 1534 // 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); 1543 attrArray = temp; 1544 } 1545 } 1546 } 1547 1548 // Finally, put all these attributes in a dictionary and filter out the duplicates. 1549 // 1550 OrderedDictionary attrDictionary = new OrderedDictionary(attrArray.Length); 1551 1552 for (int idx = 0; idx < attrArray.Length; idx++) 1553 { 1554 bool addAttr = true; 1555 if (idx >= ifaceStartIdx) { 1556 for (int ifaceSkipIdx = 0; ifaceSkipIdx < _skipInterfaceAttributeList.Length; ifaceSkipIdx++) 1557 { 1558 if (_skipInterfaceAttributeList[ifaceSkipIdx].IsInstanceOfType(attrArray[idx])) 1559 { 1560 addAttr = false; 1561 break; 1562 } 1563 } 1564 1565 } 1566 1567 if (addAttr && !attrDictionary.Contains(attrArray[idx].TypeId)) { 1568 attrDictionary[attrArray[idx].TypeId] = attrArray[idx]; 1569 } 1570 } 1571 1572 attrArray = new Attribute[attrDictionary.Count]; 1573 attrDictionary.Values.CopyTo(attrArray, 0); 1574 _attributes = new AttributeCollection(attrArray); 1575 } 1576 1577 return _attributes; 1578 } 1579 1580 /// <devdoc> 1581 /// Retrieves the class name for our type. 1582 /// </devdoc> GetClassName(object instance)1583 internal string GetClassName(object instance) 1584 { 1585 return _type.FullName; 1586 } 1587 1588 /// <devdoc> 1589 /// Retrieves the component name from the site. 1590 /// </devdoc> GetComponentName(object instance)1591 internal string GetComponentName(object instance) 1592 { 1593 IComponent comp = instance as IComponent; 1594 if (comp != null) 1595 { 1596 ISite site = comp.Site; 1597 if (site != null) 1598 { 1599 INestedSite nestedSite = site as INestedSite; 1600 if (nestedSite != null) 1601 { 1602 return nestedSite.FullName; 1603 } 1604 else 1605 { 1606 return site.Name; 1607 } 1608 } 1609 } 1610 1611 return null; 1612 } 1613 1614 /// <devdoc> 1615 /// Retrieves the type converter. If instance is non-null, 1616 /// it will be used to retrieve attributes. Otherwise, _type 1617 /// will be used. 1618 /// </devdoc> GetConverter(object instance)1619 internal TypeConverter GetConverter(object instance) 1620 { 1621 TypeConverterAttribute typeAttr = null; 1622 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. 1628 // 1629 if (instance != null) 1630 { 1631 typeAttr = (TypeConverterAttribute)TypeDescriptor.GetAttributes(_type)[typeof(TypeConverterAttribute)]; 1632 TypeConverterAttribute instanceAttr = (TypeConverterAttribute)TypeDescriptor.GetAttributes(instance)[typeof(TypeConverterAttribute)]; 1633 if (typeAttr != instanceAttr) 1634 { 1635 Type converterType = GetTypeFromName(instanceAttr.ConverterTypeName); 1636 if (converterType != null && typeof(TypeConverter).IsAssignableFrom(converterType)) 1637 { 1638 #if MONO_FEATURE_CAS 1639 try { 1640 IntSecurity.FullReflection.Assert(); 1641 #endif 1642 return (TypeConverter)ReflectTypeDescriptionProvider.CreateInstance(converterType, _type); 1643 #if MONO_FEATURE_CAS 1644 } finally { 1645 CodeAccessPermission.RevertAssert(); 1646 } 1647 #endif 1648 } 1649 } 1650 } 1651 1652 // If we got here, we return our type-based converter. 1653 // 1654 if (_converter == null) 1655 { 1656 TypeDescriptor.Trace("Converters : Building converter for {0}", _type.Name); 1657 1658 if (typeAttr == null) 1659 { 1660 typeAttr = (TypeConverterAttribute)TypeDescriptor.GetAttributes(_type)[typeof(TypeConverterAttribute)]; 1661 } 1662 1663 if (typeAttr != null) 1664 { 1665 Type converterType = GetTypeFromName(typeAttr.ConverterTypeName); 1666 if (converterType != null && typeof(TypeConverter).IsAssignableFrom(converterType)) 1667 { 1668 #if MONO_FEATURE_CAS 1669 try { 1670 IntSecurity.FullReflection.Assert(); 1671 #endif 1672 _converter = (TypeConverter)ReflectTypeDescriptionProvider.CreateInstance(converterType, _type); 1673 #if MONO_FEATURE_CAS 1674 } finally { 1675 CodeAccessPermission.RevertAssert(); 1676 } 1677 #endif 1678 } 1679 } 1680 1681 if (_converter == null) 1682 { 1683 // We did not get a converter. Traverse up the base class chain until 1684 // we find one in the stock hashtable. 1685 // 1686 _converter = (TypeConverter)ReflectTypeDescriptionProvider.SearchIntrinsicTable(IntrinsicTypeConverters, _type); 1687 Debug.Assert(_converter != null, "There is no intrinsic setup in the hashtable for the Object type"); 1688 } 1689 } 1690 1691 return _converter; 1692 } 1693 1694 /// <devdoc> 1695 /// Return the default event. The default event is determined by the 1696 /// presence of a DefaultEventAttribute on the class. 1697 /// </devdoc> GetDefaultEvent(object instance)1698 internal EventDescriptor GetDefaultEvent(object instance) 1699 { 1700 AttributeCollection attributes; 1701 1702 if (instance != null) 1703 { 1704 attributes = TypeDescriptor.GetAttributes(instance); 1705 } 1706 else 1707 { 1708 attributes = TypeDescriptor.GetAttributes(_type); 1709 } 1710 1711 DefaultEventAttribute attr = (DefaultEventAttribute)attributes[typeof(DefaultEventAttribute)]; 1712 if (attr != null && attr.Name != null) 1713 { 1714 if (instance != null) 1715 { 1716 return TypeDescriptor.GetEvents(instance)[attr.Name]; 1717 } 1718 else 1719 { 1720 return TypeDescriptor.GetEvents(_type)[attr.Name]; 1721 } 1722 } 1723 1724 return null; 1725 } 1726 1727 /// <devdoc> 1728 /// Return the default property. 1729 /// </devdoc> GetDefaultProperty(object instance)1730 internal PropertyDescriptor GetDefaultProperty(object instance) 1731 { 1732 AttributeCollection attributes; 1733 1734 if (instance != null) 1735 { 1736 attributes = TypeDescriptor.GetAttributes(instance); 1737 } 1738 else 1739 { 1740 attributes = TypeDescriptor.GetAttributes(_type); 1741 } 1742 1743 DefaultPropertyAttribute attr = (DefaultPropertyAttribute)attributes[typeof(DefaultPropertyAttribute)]; 1744 if (attr != null && attr.Name != null) 1745 { 1746 if (instance != null) 1747 { 1748 return TypeDescriptor.GetProperties(instance)[attr.Name]; 1749 } 1750 else 1751 { 1752 return TypeDescriptor.GetProperties(_type)[attr.Name]; 1753 } 1754 } 1755 1756 return null; 1757 } 1758 1759 /// <devdoc> 1760 /// Retrieves the editor for the given base type. 1761 /// </devdoc> GetEditor(object instance, Type editorBaseType)1762 internal object GetEditor(object instance, Type editorBaseType) 1763 { 1764 EditorAttribute typeAttr; 1765 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. 1771 // 1772 if (instance != null) 1773 { 1774 typeAttr = GetEditorAttribute(TypeDescriptor.GetAttributes(_type), editorBaseType); 1775 EditorAttribute instanceAttr = GetEditorAttribute(TypeDescriptor.GetAttributes(instance), editorBaseType); 1776 if (typeAttr != instanceAttr) 1777 { 1778 Type editorType = GetTypeFromName(instanceAttr.EditorTypeName); 1779 if (editorType != null && editorBaseType.IsAssignableFrom(editorType)) 1780 { 1781 return ReflectTypeDescriptionProvider.CreateInstance(editorType, _type); 1782 } 1783 } 1784 } 1785 1786 // If we got here, we return our type-based editor. 1787 // 1788 lock(this) 1789 { 1790 for (int idx = 0; idx < _editorCount; idx++) 1791 { 1792 if (_editorTypes[idx] == editorBaseType) 1793 { 1794 return _editors[idx]; 1795 } 1796 } 1797 } 1798 1799 // Editor is not cached yet. Look in the attributes. 1800 // 1801 object editor = null; 1802 1803 typeAttr = GetEditorAttribute(TypeDescriptor.GetAttributes(_type), editorBaseType); 1804 if (typeAttr != null) 1805 { 1806 Type editorType = GetTypeFromName(typeAttr.EditorTypeName); 1807 if (editorType != null && editorBaseType.IsAssignableFrom(editorType)) 1808 { 1809 editor = ReflectTypeDescriptionProvider.CreateInstance(editorType, _type); 1810 } 1811 } 1812 1813 // Editor is not in the attributes. Search intrinsic tables. 1814 // 1815 if (editor == null) 1816 { 1817 Hashtable intrinsicEditors = ReflectTypeDescriptionProvider.GetEditorTable(editorBaseType); 1818 if (intrinsicEditors != null) 1819 { 1820 editor = ReflectTypeDescriptionProvider.SearchIntrinsicTable(intrinsicEditors, _type); 1821 } 1822 1823 // As a quick sanity check, check to see that the editor we got back is of 1824 // the correct type. 1825 // 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."); 1828 editor = null; 1829 } 1830 } 1831 1832 if (editor != null) 1833 { 1834 lock(this) 1835 { 1836 if (_editorTypes == null || _editorTypes.Length == _editorCount) 1837 { 1838 int newLength = (_editorTypes == null ? 4 : _editorTypes.Length * 2); 1839 1840 Type[] newTypes = new Type[newLength]; 1841 object[] newEditors = new object[newLength]; 1842 1843 if (_editorTypes != null) 1844 { 1845 _editorTypes.CopyTo(newTypes, 0); 1846 _editors.CopyTo(newEditors, 0); 1847 } 1848 1849 _editorTypes = newTypes; 1850 _editors = newEditors; 1851 1852 _editorTypes[_editorCount] = editorBaseType; 1853 _editors[_editorCount++] = editor; 1854 } 1855 } 1856 } 1857 1858 return editor; 1859 } 1860 1861 /// <devdoc> 1862 /// Helper method to return an editor attribute of the correct base type. 1863 /// </devdoc> GetEditorAttribute(AttributeCollection attributes, Type editorBaseType)1864 private static EditorAttribute GetEditorAttribute(AttributeCollection attributes, Type editorBaseType) 1865 { 1866 foreach(Attribute attr in attributes) 1867 { 1868 EditorAttribute edAttr = attr as EditorAttribute; 1869 if (edAttr != null) 1870 { 1871 Type attrEditorBaseType = Type.GetType(edAttr.EditorBaseTypeName); 1872 1873 if (attrEditorBaseType != null && attrEditorBaseType == editorBaseType) 1874 { 1875 return edAttr; 1876 } 1877 } 1878 } 1879 1880 return null; 1881 } 1882 1883 /// <devdoc> 1884 /// Retrieves the events for this type. 1885 /// </devdoc> GetEvents()1886 internal EventDescriptorCollection GetEvents() 1887 { 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. 1891 // 1892 if (_events == null) 1893 { 1894 TypeDescriptor.Trace("Events : Building collection for {0}", _type.Name); 1895 1896 EventDescriptor[] eventArray; 1897 Dictionary<string, EventDescriptor> eventList = new Dictionary<string, EventDescriptor>(16); 1898 Type baseType = _type; 1899 Type objType = typeof(object); 1900 1901 do { 1902 eventArray = ReflectGetEvents(baseType); 1903 foreach(EventDescriptor ed in eventArray) { 1904 if (!eventList.ContainsKey(ed.Name)) { 1905 eventList.Add(ed.Name, ed); 1906 } 1907 } 1908 baseType = baseType.BaseType; 1909 } 1910 while(baseType != null && baseType != objType); 1911 1912 eventArray = new EventDescriptor[eventList.Count]; 1913 eventList.Values.CopyTo(eventArray, 0); 1914 _events = new EventDescriptorCollection(eventArray, true); 1915 } 1916 1917 return _events; 1918 } 1919 1920 /// <devdoc> 1921 /// Retrieves the properties for this type. 1922 /// </devdoc> GetProperties()1923 internal PropertyDescriptorCollection GetProperties() 1924 { 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. 1928 // 1929 if (_properties == null) 1930 { 1931 TypeDescriptor.Trace("Properties : Building collection for {0}", _type.Name); 1932 1933 PropertyDescriptor[] propertyArray; 1934 Dictionary<string, PropertyDescriptor> propertyList = new Dictionary<string, PropertyDescriptor>(10); 1935 Type baseType = _type; 1936 Type objType = typeof(object); 1937 1938 do { 1939 propertyArray = ReflectGetProperties(baseType); 1940 foreach(PropertyDescriptor p in propertyArray) { 1941 if (!propertyList.ContainsKey(p.Name)) { 1942 propertyList.Add(p.Name, p); 1943 } 1944 } 1945 baseType = baseType.BaseType; 1946 } 1947 while(baseType != null && baseType != objType); 1948 1949 propertyArray = new PropertyDescriptor[propertyList.Count]; 1950 propertyList.Values.CopyTo(propertyArray, 0); 1951 _properties = new PropertyDescriptorCollection(propertyArray, true); 1952 } 1953 1954 return _properties; 1955 } 1956 1957 /// <devdoc> 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. 1961 /// </devdoc> GetTypeFromName(string typeName)1962 private Type GetTypeFromName(string typeName) 1963 { 1964 1965 if (typeName == null || typeName.Length == 0) 1966 { 1967 return null; 1968 } 1969 1970 int commaIndex = typeName.IndexOf(','); 1971 Type t = null; 1972 1973 if (commaIndex == -1) 1974 { 1975 t = _type.Assembly.GetType(typeName); 1976 } 1977 1978 if (t == null) 1979 { 1980 t = Type.GetType(typeName); 1981 } 1982 1983 if (t == null && commaIndex != -1) 1984 { 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 1992 // resolve event. 1993 // 1994 t = Type.GetType(typeName.Substring(0, commaIndex)); 1995 } 1996 1997 return t; 1998 } 1999 2000 /// <devdoc> 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. 2004 /// </devdoc> Refresh()2005 internal void Refresh() 2006 { 2007 _attributes = null; 2008 _events = null; 2009 _properties = null; 2010 _converter = null; 2011 _editors = null; 2012 _editorTypes = null; 2013 _editorCount = 0; 2014 } 2015 } 2016 } 2017 } 2018 2019