2 // System.ComponentModel.TypeDescriptor.cs
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
8 // (C) 2002 Ximian, Inc (http://www.ximian.com)
9 // (C) 2003 Andreas Nahr
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Collections;
35 using System.Reflection;
36 using System.Globalization;
37 using System.ComponentModel.Design;
39 namespace System.ComponentModel
42 public sealed class TypeDescriptor
44 private static readonly object creatingDefaultConverters = new object ();
45 private static Hashtable defaultConverters;
46 private static IComNativeDescriptorHandler descriptorHandler;
47 private static Hashtable componentTable = new Hashtable ();
48 private static Hashtable typeTable = new Hashtable ();
50 private TypeDescriptor ()
55 public static void AddEditorTable (Type editorBaseType, Hashtable table)
57 throw new NotImplementedException ();
60 public static IDesigner CreateDesigner(IComponent component, Type designerBaseType)
62 string tn = designerBaseType.AssemblyQualifiedName;
63 AttributeCollection col = GetAttributes (component);
65 foreach (Attribute at in col) {
66 DesignerAttribute dat = at as DesignerAttribute;
67 if (dat != null && tn == dat.DesignerBaseTypeName) {
68 return (IDesigner) Activator.CreateInstance (GetTypeFromName (component, dat.DesignerTypeName));
75 public static EventDescriptor CreateEvent (Type componentType,
78 Attribute [] attributes)
80 return new ReflectionEventDescriptor (componentType, name, type, attributes);
83 public static EventDescriptor CreateEvent (Type componentType,
84 EventDescriptor oldEventDescriptor,
85 Attribute [] attributes)
87 return new ReflectionEventDescriptor (componentType, oldEventDescriptor, attributes);
90 public static PropertyDescriptor CreateProperty (Type componentType,
93 Attribute [] attributes)
95 return new ReflectionPropertyDescriptor (componentType, name, type, attributes);
98 public static PropertyDescriptor CreateProperty (Type componentType,
99 PropertyDescriptor oldPropertyDescriptor,
100 Attribute [] attributes)
102 return new ReflectionPropertyDescriptor (componentType, oldPropertyDescriptor, attributes);
105 public static AttributeCollection GetAttributes (Type componentType)
107 if (componentType == null)
108 return AttributeCollection.Empty;
110 return GetTypeInfo (componentType).GetAttributes ();
113 public static AttributeCollection GetAttributes (object component)
115 return GetAttributes (component, false);
118 public static AttributeCollection GetAttributes (object component, bool noCustomTypeDesc)
120 if (component == null)
121 return AttributeCollection.Empty;
123 if (noCustomTypeDesc == false && component is ICustomTypeDescriptor) {
124 return ((ICustomTypeDescriptor) component).GetAttributes ();
126 IComponent com = component as IComponent;
128 return GetComponentInfo (com).GetAttributes ();
130 return GetTypeInfo (component.GetType()).GetAttributes ();
134 public static string GetClassName (object component)
136 return GetClassName (component, false);
139 public static string GetClassName (object component, bool noCustomTypeDesc)
141 if (component == null)
142 throw new ArgumentNullException ("component", "component cannot be null");
144 if (noCustomTypeDesc == false && component is ICustomTypeDescriptor) {
145 return ((ICustomTypeDescriptor) component).GetClassName ();
147 return component.GetType ().FullName;
151 public static string GetComponentName (object component)
153 return GetComponentName (component, false);
156 public static string GetComponentName (object component, bool noCustomTypeDesc)
158 if (component == null)
159 throw new ArgumentNullException ("component", "component cannot be null");
161 if (noCustomTypeDesc == false && component is ICustomTypeDescriptor) {
162 return ((ICustomTypeDescriptor) component).GetComponentName ();
164 IComponent c = component as IComponent;
165 if (c != null && c.Site != null)
172 return component.GetType().Name;
176 public static TypeConverter GetConverter (object component)
178 return GetConverter (component.GetType ());
181 public static TypeConverter GetConverter (object component, bool noCustomTypeDesc)
183 if (component == null)
184 throw new ArgumentNullException ("component", "component cannot be null");
186 if (noCustomTypeDesc == false && component is ICustomTypeDescriptor) {
187 return ((ICustomTypeDescriptor) component).GetConverter ();
191 AttributeCollection atts = GetAttributes (component, false);
192 TypeConverterAttribute tca = (TypeConverterAttribute) atts[typeof(TypeConverterAttribute)];
193 if (tca != null && tca.ConverterTypeName.Length > 0) {
194 t = GetTypeFromName (component as IComponent, tca.ConverterTypeName);
198 ConstructorInfo ci = t.GetConstructor (new Type[] { typeof(Type) });
200 return (TypeConverter) ci.Invoke (new object[] { component.GetType () });
202 return (TypeConverter) Activator.CreateInstance (t);
205 return GetConverter (component.GetType ());
209 private static Hashtable DefaultConverters
212 lock (creatingDefaultConverters) {
213 if (defaultConverters != null)
214 return defaultConverters;
216 defaultConverters = new Hashtable ();
217 defaultConverters.Add (typeof (bool), typeof (BooleanConverter));
218 defaultConverters.Add (typeof (byte), typeof (ByteConverter));
219 defaultConverters.Add (typeof (sbyte), typeof (SByteConverter));
220 defaultConverters.Add (typeof (string), typeof (StringConverter));
221 defaultConverters.Add (typeof (char), typeof (CharConverter));
222 defaultConverters.Add (typeof (short), typeof (Int16Converter));
223 defaultConverters.Add (typeof (int), typeof (Int32Converter));
224 defaultConverters.Add (typeof (long), typeof (Int64Converter));
225 defaultConverters.Add (typeof (ushort), typeof (UInt16Converter));
226 defaultConverters.Add (typeof (uint), typeof (UInt32Converter));
227 defaultConverters.Add (typeof (ulong), typeof (UInt64Converter));
228 defaultConverters.Add (typeof (float), typeof (SingleConverter));
229 defaultConverters.Add (typeof (double), typeof (DoubleConverter));
230 defaultConverters.Add (typeof (decimal), typeof (DecimalConverter));
231 defaultConverters.Add (typeof (object), typeof (TypeConverter));
232 defaultConverters.Add (typeof (void), typeof (TypeConverter));
233 defaultConverters.Add (typeof (Array), typeof (ArrayConverter));
234 defaultConverters.Add (typeof (CultureInfo), typeof (CultureInfoConverter));
235 defaultConverters.Add (typeof (DateTime), typeof (DateTimeConverter));
236 defaultConverters.Add (typeof (Guid), typeof (GuidConverter));
237 defaultConverters.Add (typeof (TimeSpan), typeof (TimeSpanConverter));
238 defaultConverters.Add (typeof (ICollection), typeof (CollectionConverter));
240 return defaultConverters;
244 public static TypeConverter GetConverter (Type type)
246 TypeConverterAttribute tca = null;
248 object [] atts = type.GetCustomAttributes (typeof(TypeConverterAttribute), true);
251 tca = (TypeConverterAttribute)atts[0];
254 t = GetTypeFromName (null, tca.ConverterTypeName);
259 // EnumConverter needs to know the enum type
260 return new EnumConverter(type);
261 } else if (type.IsArray) {
262 return new ArrayConverter ();
267 t = FindConverterType (type);
270 Exception exc = null;
272 return (TypeConverter) Activator.CreateInstance (t);
273 } catch (MissingMethodException e) {
278 return (TypeConverter) Activator.CreateInstance (t, new object [] {type});
279 } catch (MissingMethodException e) {
284 return new ReferenceConverter (type); // Default?
287 private static Type FindConverterType (Type type)
291 // Is there a default converter
292 t = (Type) DefaultConverters [type];
296 // Find default converter with a type this type is assignable to
297 foreach (Type defType in DefaultConverters.Keys) {
298 if (defType.IsInterface && defType.IsAssignableFrom (type)) {
299 return (Type) DefaultConverters [defType];
303 // Nothing found, try the same with our base type
304 if (type.BaseType != null)
305 return FindConverterType (type.BaseType);
310 public static EventDescriptor GetDefaultEvent (Type componentType)
312 return GetTypeInfo (componentType).GetDefaultEvent ();
315 public static EventDescriptor GetDefaultEvent (object component)
317 return GetDefaultEvent (component, false);
320 public static EventDescriptor GetDefaultEvent (object component, bool noCustomTypeDesc)
322 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
323 return ((ICustomTypeDescriptor) component).GetDefaultEvent ();
325 IComponent com = component as IComponent;
327 return GetComponentInfo (com).GetDefaultEvent ();
329 return GetTypeInfo (component.GetType()).GetDefaultEvent ();
333 public static PropertyDescriptor GetDefaultProperty (Type componentType)
335 return GetTypeInfo (componentType).GetDefaultProperty ();
338 public static PropertyDescriptor GetDefaultProperty (object component)
340 return GetDefaultProperty (component, false);
343 public static PropertyDescriptor GetDefaultProperty (object component, bool noCustomTypeDesc)
345 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
346 return ((ICustomTypeDescriptor) component).GetDefaultProperty ();
348 IComponent com = component as IComponent;
350 return GetComponentInfo (com).GetDefaultProperty ();
352 return GetTypeInfo (component.GetType()).GetDefaultProperty ();
356 public static object GetEditor (Type componentType, Type editorBaseType)
359 object [] atts = componentType.GetCustomAttributes (typeof(EditorAttribute), true);
360 if (atts == null || atts.Length == 0)
364 foreach (EditorAttribute ea in atts)
366 t = GetTypeFromName (null, ea.EditorTypeName);
367 if (t.IsSubclassOf(editorBaseType))
372 Exception exc = null;
374 return Activator.CreateInstance (t);
375 } catch (MissingMethodException e) {
380 return Activator.CreateInstance (t, new object [] {componentType});
381 } catch (MissingMethodException e) {
386 return null; // No editor specified
389 public static object GetEditor (object component, Type editorBaseType)
391 return GetEditor (component, editorBaseType, false);
395 public static object GetEditor (object component, Type editorBaseType, bool noCustomTypeDesc)
397 throw new NotImplementedException ();
400 public static EventDescriptorCollection GetEvents (object component)
402 return GetEvents (component, false);
405 public static EventDescriptorCollection GetEvents (Type componentType)
407 return GetEvents (componentType, null);
410 public static EventDescriptorCollection GetEvents (object component, Attribute [] attributes)
412 return GetEvents (component, attributes, false);
415 public static EventDescriptorCollection GetEvents (object component, bool noCustomTypeDesc)
417 return GetEvents (component, null, noCustomTypeDesc);
420 public static EventDescriptorCollection GetEvents (Type componentType, Attribute [] attributes)
422 return GetTypeInfo (componentType).GetEvents (attributes);
425 public static EventDescriptorCollection GetEvents (object component, Attribute [] attributes, bool noCustomTypeDesc)
427 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
428 return ((ICustomTypeDescriptor) component).GetEvents (attributes);
430 IComponent com = component as IComponent;
432 return GetComponentInfo (com).GetEvents (attributes);
434 return GetTypeInfo (component.GetType()).GetEvents (attributes);
438 public static PropertyDescriptorCollection GetProperties (object component)
440 return GetProperties (component, false);
443 public static PropertyDescriptorCollection GetProperties (Type componentType)
445 return GetProperties (componentType, null);
448 public static PropertyDescriptorCollection GetProperties (object component, Attribute [] attributes)
450 return GetProperties (component, attributes, false);
453 public static PropertyDescriptorCollection GetProperties (object component, Attribute [] attributes, bool noCustomTypeDesc)
455 if (component == null)
456 throw new ArgumentNullException ("component");
458 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
459 return ((ICustomTypeDescriptor) component).GetProperties (attributes);
461 IComponent com = component as IComponent;
463 return GetComponentInfo (com).GetProperties (attributes);
465 return GetTypeInfo (component.GetType()).GetProperties (attributes);
469 public static PropertyDescriptorCollection GetProperties (object component, bool noCustomTypeDesc)
471 return GetProperties (component, null, noCustomTypeDesc);
474 public static PropertyDescriptorCollection GetProperties (Type componentType, Attribute [] attributes)
476 return GetTypeInfo (componentType).GetProperties (attributes);
479 public static void SortDescriptorArray (IList infos)
481 string[] names = new string [infos.Count];
482 object[] values = new object [infos.Count];
483 for (int n=0; n<names.Length; n++) {
484 names[n] = ((MemberDescriptor)infos[n]).Name;
485 values[n] = infos[n];
487 Array.Sort (names, values);
489 foreach (object ob in values)
493 public static IComNativeDescriptorHandler ComNativeDescriptorHandler {
494 get { return descriptorHandler; }
495 set { descriptorHandler = value; }
498 public static void Refresh (Assembly assembly)
500 foreach (Type type in assembly.GetTypes())
504 public static void Refresh (Module module)
506 foreach (Type type in module.GetTypes())
510 public static void Refresh (object component)
512 lock (componentTable)
514 componentTable.Remove (component);
516 if (Refreshed != null) Refreshed (new RefreshEventArgs (component));
519 public static void Refresh (Type type)
523 typeTable.Remove (type);
525 if (Refreshed != null) Refreshed (new RefreshEventArgs (type));
528 static EventHandler onDispose;
530 static void OnComponentDisposed (object sender, EventArgs args)
532 lock (componentTable) {
533 componentTable.Remove (sender);
537 public static event RefreshEventHandler Refreshed;
539 internal static ComponentInfo GetComponentInfo (IComponent com)
541 lock (componentTable)
543 ComponentInfo ci = (ComponentInfo) componentTable [com];
545 if (onDispose == null)
546 onDispose = new EventHandler (OnComponentDisposed);
548 com.Disposed += onDispose;
549 ci = new ComponentInfo (com);
550 componentTable [com] = ci;
556 internal static TypeInfo GetTypeInfo (Type type)
560 TypeInfo ci = (TypeInfo) typeTable [type];
562 ci = new TypeInfo (type);
563 typeTable [type] = ci;
569 static Type GetTypeFromName (IComponent component, string typeName)
571 if (component != null && component.Site != null) {
572 ITypeResolutionService resver = (ITypeResolutionService) component.Site.GetService (typeof(ITypeResolutionService));
573 if (resver != null) return resver.GetType (typeName, true, false);
576 Type t = Type.GetType (typeName);
577 if (t == null) throw new ArgumentException ("Type '" + typeName + "' not found");
582 internal abstract class Info
585 EventDescriptor _defaultEvent;
586 bool _gotDefaultEvent;
587 PropertyDescriptor _defaultProperty;
588 bool _gotDefaultProperty;
589 AttributeCollection _attributes;
591 public Info (Type infoType)
593 _infoType = infoType;
596 public abstract AttributeCollection GetAttributes ();
597 public abstract EventDescriptorCollection GetEvents ();
598 public abstract PropertyDescriptorCollection GetProperties ();
602 get { return _infoType; }
605 public EventDescriptorCollection GetEvents (Attribute[] attributes)
607 EventDescriptorCollection evs = GetEvents ();
608 if (attributes == null) return evs;
609 else return evs.Filter (attributes);
612 public PropertyDescriptorCollection GetProperties (Attribute[] attributes)
614 PropertyDescriptorCollection props = GetProperties ();
615 if (attributes == null) return props;
616 else return props.Filter (attributes);
619 public EventDescriptor GetDefaultEvent ()
621 if (_gotDefaultEvent) return _defaultEvent;
623 DefaultEventAttribute attr = (DefaultEventAttribute) GetAttributes()[typeof(DefaultEventAttribute)];
624 if (attr == null || attr.Name == null)
625 _defaultEvent = null;
627 EventDescriptorCollection events = GetEvents ();
628 _defaultEvent = events [attr.Name];
630 // In our test case (TypeDescriptorTest.TestGetDefaultEvent), we have
631 // a scenario where a custom filter adds the DefaultEventAttribute,
632 // but its FilterEvents method removes the event the
633 // DefaultEventAttribute applied to. .NET 1.x accepts this and returns
634 // the *other* event defined in the class.
636 // Consequently, we know we have a DefaultEvent, but we need to check
637 // and ensure that the requested event is unfiltered. If it is, just
638 // grab the first element in the collection.
639 if (_defaultEvent == null && events.Count > 0)
640 _defaultEvent = events [0];
643 _gotDefaultEvent = true;
644 return _defaultEvent;
647 public PropertyDescriptor GetDefaultProperty ()
649 if (_gotDefaultProperty) return _defaultProperty;
651 DefaultPropertyAttribute attr = (DefaultPropertyAttribute) GetAttributes()[typeof(DefaultPropertyAttribute)];
652 if (attr == null || attr.Name == null)
653 _defaultProperty = null;
655 PropertyDescriptorCollection properties = GetProperties ();
656 _defaultProperty = properties[attr.Name];
658 _gotDefaultProperty = true;
659 return _defaultProperty;
662 protected AttributeCollection GetAttributes (IComponent comp)
664 if (_attributes != null) return _attributes;
667 object[] ats = _infoType.GetCustomAttributes (true);
668 Hashtable t = new Hashtable ();
669 foreach (Attribute at in ats)
672 if (comp != null && comp.Site != null)
674 ITypeDescriptorFilterService filter = (ITypeDescriptorFilterService) comp.Site.GetService (typeof(ITypeDescriptorFilterService));
675 cache = filter.FilterAttributes (comp, t);
678 ArrayList atts = new ArrayList ();
679 atts.AddRange (t.Values);
680 AttributeCollection attCol = new AttributeCollection (atts);
681 if (cache) _attributes = attCol;
686 internal class ComponentInfo : Info
688 IComponent _component;
689 EventDescriptorCollection _events;
690 PropertyDescriptorCollection _properties;
692 public ComponentInfo (IComponent component): base (component.GetType())
694 _component = component;
697 public override AttributeCollection GetAttributes ()
699 return base.GetAttributes (_component);
702 public override EventDescriptorCollection GetEvents ()
704 if (_events != null) return _events;
707 EventInfo[] events = _component.GetType().GetEvents ();
708 Hashtable t = new Hashtable ();
709 foreach (EventInfo ev in events)
710 t [ev.Name] = new ReflectionEventDescriptor (ev);
712 if (_component.Site != null)
714 ITypeDescriptorFilterService filter = (ITypeDescriptorFilterService) _component.Site.GetService (typeof(ITypeDescriptorFilterService));
715 cache = filter.FilterEvents (_component, t);
718 ArrayList atts = new ArrayList ();
719 atts.AddRange (t.Values);
720 EventDescriptorCollection attCol = new EventDescriptorCollection (atts);
721 if (cache) _events = attCol;
725 public override PropertyDescriptorCollection GetProperties ()
727 if (_properties != null) return _properties;
730 PropertyInfo[] props = _component.GetType().GetProperties ();
731 Hashtable t = new Hashtable ();
732 foreach (PropertyInfo pr in props)
733 t [pr.Name] = new ReflectionPropertyDescriptor (pr);
735 if (_component.Site != null)
737 ITypeDescriptorFilterService filter = (ITypeDescriptorFilterService) _component.Site.GetService (typeof(ITypeDescriptorFilterService));
738 cache = filter.FilterProperties (_component, t);
741 PropertyDescriptor[] descriptors = new PropertyDescriptor[t.Values.Count];
742 t.Values.CopyTo (descriptors, 0);
743 PropertyDescriptorCollection attCol = new PropertyDescriptorCollection (descriptors, true);
744 if (cache) _properties = attCol;
749 internal class TypeInfo : Info
751 EventDescriptorCollection _events;
752 PropertyDescriptorCollection _properties;
754 public TypeInfo (Type t): base (t)
758 public override AttributeCollection GetAttributes ()
760 return base.GetAttributes (null);
763 public override EventDescriptorCollection GetEvents ()
765 if (_events != null) return _events;
767 EventInfo[] events = InfoType.GetEvents ();
768 EventDescriptor[] descs = new EventDescriptor [events.Length];
769 for (int n=0; n<events.Length; n++)
770 descs [n] = new ReflectionEventDescriptor (events[n]);
772 _events = new EventDescriptorCollection (descs);
776 public override PropertyDescriptorCollection GetProperties ()
778 if (_properties != null) return _properties;
780 PropertyInfo[] props = InfoType.GetProperties ();
781 PropertyDescriptor[] descs = new PropertyDescriptor [props.Length];
782 for (int n=0; n<props.Length; n++)
783 descs [n] = new ReflectionPropertyDescriptor (props[n]);
785 _properties = new PropertyDescriptorCollection (descs, true);