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 string creatingDefaultConverters = "creatingDefaultConverters";
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 if (defaultConverters != null)
213 return defaultConverters;
215 lock (creatingDefaultConverters) {
216 if (defaultConverters != null)
217 return defaultConverters;
219 defaultConverters = new Hashtable ();
220 defaultConverters.Add (typeof (bool), typeof (BooleanConverter));
221 defaultConverters.Add (typeof (byte), typeof (ByteConverter));
222 defaultConverters.Add (typeof (sbyte), typeof (SByteConverter));
223 defaultConverters.Add (typeof (string), typeof (StringConverter));
224 defaultConverters.Add (typeof (char), typeof (CharConverter));
225 defaultConverters.Add (typeof (short), typeof (Int16Converter));
226 defaultConverters.Add (typeof (int), typeof (Int32Converter));
227 defaultConverters.Add (typeof (long), typeof (Int64Converter));
228 defaultConverters.Add (typeof (ushort), typeof (UInt16Converter));
229 defaultConverters.Add (typeof (uint), typeof (UInt32Converter));
230 defaultConverters.Add (typeof (ulong), typeof (UInt64Converter));
231 defaultConverters.Add (typeof (float), typeof (SingleConverter));
232 defaultConverters.Add (typeof (double), typeof (DoubleConverter));
233 defaultConverters.Add (typeof (decimal), typeof (DecimalConverter));
234 defaultConverters.Add (typeof (object), typeof (TypeConverter));
235 defaultConverters.Add (typeof (void), typeof (TypeConverter));
236 defaultConverters.Add (typeof (Array), typeof (ArrayConverter));
237 defaultConverters.Add (typeof (CultureInfo), typeof (CultureInfoConverter));
238 defaultConverters.Add (typeof (DateTime), typeof (DateTimeConverter));
239 defaultConverters.Add (typeof (Guid), typeof (GuidConverter));
240 defaultConverters.Add (typeof (TimeSpan), typeof (TimeSpanConverter));
241 defaultConverters.Add (typeof (ICollection), typeof (CollectionConverter));
243 return defaultConverters;
247 public static TypeConverter GetConverter (Type type)
249 TypeConverterAttribute tca = null;
251 object [] atts = type.GetCustomAttributes (typeof(TypeConverterAttribute), true);
254 tca = (TypeConverterAttribute)atts[0];
257 t = GetTypeFromName (null, tca.ConverterTypeName);
262 // EnumConverter needs to know the enum type
263 return new EnumConverter(type);
264 } else if (type.IsArray) {
265 return new ArrayConverter ();
270 t = FindConverterType (type);
\r
273 Exception exc = null;
275 return (TypeConverter) Activator.CreateInstance (t);
276 } catch (MissingMethodException e) {
281 return (TypeConverter) Activator.CreateInstance (t, new object [] {type});
282 } catch (MissingMethodException e) {
287 return new ReferenceConverter (type); // Default?
290 private static Type FindConverterType (Type type)
\r
294 // Is there a default converter
\r
295 t = (Type) DefaultConverters [type];
\r
299 // Find default converter with a type this type is assignable to
\r
300 foreach (Type defType in DefaultConverters.Keys) {
\r
301 if (defType.IsInterface && defType.IsAssignableFrom (type)) {
\r
302 return (Type) DefaultConverters [defType];
\r
306 // Nothing found, try the same with our base type
\r
307 if (type.BaseType != null)
\r
308 return FindConverterType (type.BaseType);
\r
313 public static EventDescriptor GetDefaultEvent (Type componentType)
315 return GetTypeInfo (componentType).GetDefaultEvent ();
318 public static EventDescriptor GetDefaultEvent (object component)
320 return GetDefaultEvent (component, false);
323 public static EventDescriptor GetDefaultEvent (object component, bool noCustomTypeDesc)
325 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
326 return ((ICustomTypeDescriptor) component).GetDefaultEvent ();
328 IComponent com = component as IComponent;
330 return GetComponentInfo (com).GetDefaultEvent ();
332 return GetTypeInfo (component.GetType()).GetDefaultEvent ();
336 public static PropertyDescriptor GetDefaultProperty (Type componentType)
338 return GetTypeInfo (componentType).GetDefaultProperty ();
341 public static PropertyDescriptor GetDefaultProperty (object component)
343 return GetDefaultProperty (component, false);
346 public static PropertyDescriptor GetDefaultProperty (object component, bool noCustomTypeDesc)
348 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
349 return ((ICustomTypeDescriptor) component).GetDefaultProperty ();
351 IComponent com = component as IComponent;
353 return GetComponentInfo (com).GetDefaultProperty ();
355 return GetTypeInfo (component.GetType()).GetDefaultProperty ();
359 public static object GetEditor (Type componentType, Type editorBaseType)
362 object [] atts = componentType.GetCustomAttributes (typeof(EditorAttribute), true);
363 if (atts == null || atts.Length == 0)
367 foreach (EditorAttribute ea in atts)
369 t = GetTypeFromName (null, ea.EditorTypeName);
370 if (t.IsSubclassOf(editorBaseType))
375 Exception exc = null;
377 return Activator.CreateInstance (t);
378 } catch (MissingMethodException e) {
383 return Activator.CreateInstance (t, new object [] {componentType});
384 } catch (MissingMethodException e) {
389 return null; // No editor specified
392 public static object GetEditor (object component, Type editorBaseType)
394 return GetEditor (component, editorBaseType, false);
398 public static object GetEditor (object component, Type editorBaseType, bool noCustomTypeDesc)
400 throw new NotImplementedException ();
403 public static EventDescriptorCollection GetEvents (object component)
405 return GetEvents (component, false);
408 public static EventDescriptorCollection GetEvents (Type componentType)
410 return GetEvents (componentType, null);
413 public static EventDescriptorCollection GetEvents (object component, Attribute [] attributes)
415 return GetEvents (component, attributes, false);
418 public static EventDescriptorCollection GetEvents (object component, bool noCustomTypeDesc)
420 return GetEvents (component, null, noCustomTypeDesc);
423 public static EventDescriptorCollection GetEvents (Type componentType, Attribute [] attributes)
425 return GetTypeInfo (componentType).GetEvents (attributes);
428 public static EventDescriptorCollection GetEvents (object component, Attribute [] attributes, bool noCustomTypeDesc)
430 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
431 return ((ICustomTypeDescriptor) component).GetEvents (attributes);
433 IComponent com = component as IComponent;
435 return GetComponentInfo (com).GetEvents (attributes);
437 return GetTypeInfo (component.GetType()).GetEvents (attributes);
441 public static PropertyDescriptorCollection GetProperties (object component)
443 return GetProperties (component, false);
446 public static PropertyDescriptorCollection GetProperties (Type componentType)
448 return GetProperties (componentType, null);
451 public static PropertyDescriptorCollection GetProperties (object component, Attribute [] attributes)
453 return GetProperties (component, attributes, false);
456 public static PropertyDescriptorCollection GetProperties (object component, Attribute [] attributes, bool noCustomTypeDesc)
458 if (component == null)
459 throw new ArgumentNullException ("component");
461 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
462 return ((ICustomTypeDescriptor) component).GetProperties (attributes);
464 IComponent com = component as IComponent;
466 return GetComponentInfo (com).GetProperties (attributes);
468 return GetTypeInfo (component.GetType()).GetProperties (attributes);
472 public static PropertyDescriptorCollection GetProperties (object component, bool noCustomTypeDesc)
474 return GetProperties (component, null, noCustomTypeDesc);
477 public static PropertyDescriptorCollection GetProperties (Type componentType, Attribute [] attributes)
479 return GetTypeInfo (componentType).GetProperties (attributes);
482 public static void SortDescriptorArray (IList infos)
484 string[] names = new string [infos.Count];
485 object[] values = new object [infos.Count];
486 for (int n=0; n<names.Length; n++) {
487 names[n] = ((MemberDescriptor)infos[n]).Name;
488 values[n] = infos[n];
490 Array.Sort (names, values);
492 foreach (object ob in values)
496 public static IComNativeDescriptorHandler ComNativeDescriptorHandler {
497 get { return descriptorHandler; }
498 set { descriptorHandler = value; }
501 public static void Refresh (Assembly assembly)
503 foreach (Type type in assembly.GetTypes())
507 public static void Refresh (Module module)
509 foreach (Type type in module.GetTypes())
513 public static void Refresh (object component)
515 lock (componentTable)
517 componentTable.Remove (component);
519 if (Refreshed != null) Refreshed (new RefreshEventArgs (component));
522 public static void Refresh (Type type)
526 typeTable.Remove (type);
528 if (Refreshed != null) Refreshed (new RefreshEventArgs (type));
531 static EventHandler onDispose;
533 static void OnComponentDisposed (object sender, EventArgs args)
535 lock (componentTable) {
536 componentTable.Remove (sender);
540 public static event RefreshEventHandler Refreshed;
542 internal static ComponentInfo GetComponentInfo (IComponent com)
544 lock (componentTable)
546 ComponentInfo ci = (ComponentInfo) componentTable [com];
548 if (onDispose == null)
549 onDispose = new EventHandler (OnComponentDisposed);
551 com.Disposed += onDispose;
552 ci = new ComponentInfo (com);
553 componentTable [com] = ci;
559 internal static TypeInfo GetTypeInfo (Type type)
563 TypeInfo ci = (TypeInfo) typeTable [type];
565 ci = new TypeInfo (type);
566 typeTable [type] = ci;
572 static Type GetTypeFromName (IComponent component, string typeName)
574 if (component != null && component.Site != null) {
575 ITypeResolutionService resver = (ITypeResolutionService) component.Site.GetService (typeof(ITypeResolutionService));
576 if (resver != null) return resver.GetType (typeName, true, false);
579 Type t = Type.GetType (typeName);
580 if (t == null) throw new ArgumentException ("Type '" + typeName + "' not found");
585 internal abstract class Info
588 EventDescriptor _defaultEvent;
589 bool _gotDefaultEvent;
590 PropertyDescriptor _defaultProperty;
591 bool _gotDefaultProperty;
592 AttributeCollection _attributes;
594 public Info (Type infoType)
596 _infoType = infoType;
599 public abstract AttributeCollection GetAttributes ();
600 public abstract EventDescriptorCollection GetEvents ();
601 public abstract PropertyDescriptorCollection GetProperties ();
605 get { return _infoType; }
608 public EventDescriptorCollection GetEvents (Attribute[] attributes)
610 EventDescriptorCollection evs = GetEvents ();
611 if (attributes == null) return evs;
612 else return evs.Filter (attributes);
615 public PropertyDescriptorCollection GetProperties (Attribute[] attributes)
617 PropertyDescriptorCollection props = GetProperties ();
618 if (attributes == null) return props;
619 else return props.Filter (attributes);
622 public EventDescriptor GetDefaultEvent ()
624 if (_gotDefaultEvent) return _defaultEvent;
626 DefaultEventAttribute attr = (DefaultEventAttribute) GetAttributes()[typeof(DefaultEventAttribute)];
627 if (attr == null || attr.Name == null)
628 _defaultEvent = null;
630 EventDescriptorCollection events = GetEvents ();
631 _defaultEvent = events [attr.Name];
633 // In our test case (TypeDescriptorTest.TestGetDefaultEvent), we have
634 // a scenario where a custom filter adds the DefaultEventAttribute,
635 // but its FilterEvents method removes the event the
636 // DefaultEventAttribute applied to. .NET 1.x accepts this and returns
637 // the *other* event defined in the class.
639 // Consequently, we know we have a DefaultEvent, but we need to check
640 // and ensure that the requested event is unfiltered. If it is, just
641 // grab the first element in the collection.
642 if (_defaultEvent == null && events.Count > 0)
643 _defaultEvent = events [0];
646 _gotDefaultEvent = true;
647 return _defaultEvent;
650 public PropertyDescriptor GetDefaultProperty ()
652 if (_gotDefaultProperty) return _defaultProperty;
654 DefaultPropertyAttribute attr = (DefaultPropertyAttribute) GetAttributes()[typeof(DefaultPropertyAttribute)];
655 if (attr == null || attr.Name == null)
656 _defaultProperty = null;
658 PropertyDescriptorCollection properties = GetProperties ();
659 _defaultProperty = properties[attr.Name];
661 _gotDefaultProperty = true;
662 return _defaultProperty;
665 protected AttributeCollection GetAttributes (IComponent comp)
667 if (_attributes != null) return _attributes;
670 object[] ats = _infoType.GetCustomAttributes (true);
671 Hashtable t = new Hashtable ();
672 foreach (Attribute at in ats)
675 if (comp != null && comp.Site != null)
677 ITypeDescriptorFilterService filter = (ITypeDescriptorFilterService) comp.Site.GetService (typeof(ITypeDescriptorFilterService));
678 cache = filter.FilterAttributes (comp, t);
681 ArrayList atts = new ArrayList ();
682 atts.AddRange (t.Values);
683 AttributeCollection attCol = new AttributeCollection (atts);
684 if (cache) _attributes = attCol;
689 internal class ComponentInfo : Info
691 IComponent _component;
692 EventDescriptorCollection _events;
693 PropertyDescriptorCollection _properties;
695 public ComponentInfo (IComponent component): base (component.GetType())
697 _component = component;
700 public override AttributeCollection GetAttributes ()
702 return base.GetAttributes (_component);
705 public override EventDescriptorCollection GetEvents ()
707 if (_events != null) return _events;
710 EventInfo[] events = _component.GetType().GetEvents ();
711 Hashtable t = new Hashtable ();
712 foreach (EventInfo ev in events)
713 t [ev.Name] = new ReflectionEventDescriptor (ev);
715 if (_component.Site != null)
717 ITypeDescriptorFilterService filter = (ITypeDescriptorFilterService) _component.Site.GetService (typeof(ITypeDescriptorFilterService));
718 cache = filter.FilterEvents (_component, t);
721 ArrayList atts = new ArrayList ();
722 atts.AddRange (t.Values);
723 EventDescriptorCollection attCol = new EventDescriptorCollection (atts);
724 if (cache) _events = attCol;
728 public override PropertyDescriptorCollection GetProperties ()
730 if (_properties != null) return _properties;
733 PropertyInfo[] props = _component.GetType().GetProperties ();
734 Hashtable t = new Hashtable ();
735 foreach (PropertyInfo pr in props)
736 t [pr.Name] = new ReflectionPropertyDescriptor (pr);
738 if (_component.Site != null)
740 ITypeDescriptorFilterService filter = (ITypeDescriptorFilterService) _component.Site.GetService (typeof(ITypeDescriptorFilterService));
741 cache = filter.FilterProperties (_component, t);
744 ArrayList atts = new ArrayList ();
745 atts.AddRange (t.Values);
746 PropertyDescriptorCollection attCol = new PropertyDescriptorCollection (atts);
747 if (cache) _properties = attCol;
752 internal class TypeInfo : Info
754 EventDescriptorCollection _events;
755 PropertyDescriptorCollection _properties;
757 public TypeInfo (Type t): base (t)
761 public override AttributeCollection GetAttributes ()
763 return base.GetAttributes (null);
766 public override EventDescriptorCollection GetEvents ()
768 if (_events != null) return _events;
770 EventInfo[] events = InfoType.GetEvents ();
771 EventDescriptor[] descs = new EventDescriptor [events.Length];
772 for (int n=0; n<events.Length; n++)
773 descs [n] = new ReflectionEventDescriptor (events[n]);
775 _events = new EventDescriptorCollection (descs);
779 public override PropertyDescriptorCollection GetProperties ()
781 if (_properties != null) return _properties;
783 PropertyInfo[] props = InfoType.GetProperties ();
784 PropertyDescriptor[] descs = new PropertyDescriptor [props.Length];
785 for (int n=0; n<props.Length; n++)
786 descs [n] = new ReflectionPropertyDescriptor (props[n]);
788 _properties = new PropertyDescriptorCollection (descs);